Loading [MathJax]/extensions/tex2jax.js
Finite Volume Solver  prototype
A framework to build finite volume solvers for the AG Klein at the Freie Universität Berlin.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
span.hpp
Go to the documentation of this file.
1 // Copyright (c) 2017-2018 Maikel Nadolski
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 //
10 // The above copyright notice and this permission notice shall be included in
11 // all copies or substantial portions of the Software.
12 //
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 // SOFTWARE.
20 
21 #ifndef FUB_CORE_SPAN_HPP
22 #define FUB_CORE_SPAN_HPP
23 
24 #include "fub/core/assert.hpp"
26 #include "fub/core/pragma.hpp"
27 #include "fub/core/type_traits.hpp"
28 
29 #include <array>
30 #include <type_traits>
31 
32 namespace fub {
33 /// \defgroup spans Spans
34 /// Types and function which are about non-owning ranges of contiguous memory.
35 
36 namespace detail {
37 /// @{
38 /// Tests if the specified type `T` is a `std::array<U, N>` for some U and N.
39 template <typename T> struct is_std_array : std::false_type {};
40 template <typename T, std::size_t N>
41 struct is_std_array<std::array<T, N>> : std::true_type {};
42 /// @}
43 
44 template <typename T> using data_t = decltype(std::declval<T>().data());
45 template <typename T> using element_type_ = std::remove_pointer_t<data_t<T>>;
46 template <typename T> using array_type_t = element_type_<T> (*)[];
47 } // namespace detail
48 
49 template <typename T, std::ptrdiff_t N> class span;
50 
51 ///////////////////////////////////////////////////////////////////////////////
52 // [span.traits.is_span]
53 
54 /// Returns true if the specified T is a `span<S, N>` for some type S and
55 /// integer N.
56 template <typename T> struct is_span : std::false_type {};
57 
58 /// Returns true if the specified T is a `span<S, N>` for some type S and
59 /// integer N.
60 template <typename T, std::ptrdiff_t N>
61 struct is_span<span<T, N>> : std::true_type {};
62 
63 /// Returns true if the specified T is a `span<S, N>` for some type S and
64 /// integer N.
65 template <typename T> static constexpr bool is_span_v = is_span<T>::value;
66 
67 ///////////////////////////////////////////////////////////////////////////////
68 // [span.class]
69 
70 /// \ingroup spans
71 /// A span is a view over a contiguous sequence of objects, the storage of which
72 /// is owned by some other object.
73 ///
74 /// All member functions of span have constant time complexity.
75 ///
76 /// `T` is required to be a complete object type that is not an abstract
77 /// class type.
78 ///
79 /// If `N` is negative and not equal to dynamic_­extent, the program is
80 /// ill-formed.
81 template <typename T, std::ptrdiff_t N = dynamic_extent> class span {
82 public:
83  static_assert(N > 0, "span's extent needs to be non-negative.");
84 
85  using element_type = T;
86  using pointer = T*;
87  using reference = T&;
88  using value_type = std::remove_cv_t<T>;
89  using index_type = std::ptrdiff_t;
90  using difference_type = std::ptrdiff_t;
91  using iterator = pointer;
92  using const_iterator = std::add_const_t<T>*;
93  using reverse_iterator = std::reverse_iterator<iterator>;
94  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
95 
96  static constexpr index_type extent = N;
97  static constexpr std::size_t sextent = static_cast<std::size_t>(N);
98 
99  /// \name Constructors, copy, and assignment [span.cons]
100 
101  /// Constructs a span from a `pointer` and `size` pair.
102  ///
103  /// This performs an assertion check in debug builds which will terminate the
104  /// application if the specified size does not match the extent.
105  ///
106  /// \param[in] p a valid address pointing to the first element of the span.
107  /// \param[in] size the size such that `[p, p + size)` is a valid range.
108  ///
109  /// \pre `size == extent`
110  ///
111  /// \post `data() == p`
112  /// \post `size() == size`
113  ///
114  /// \throws Nothing.
115  constexpr span(pointer p, [[maybe_unused]] index_type size) : pointer_{p} {
116  FUB_ASSERT(size == extent);
117  }
118 
119  /// Constructs a span from two pointers.
120  ///
121  /// This performs an assertion check in debug builds which will terminate the
122  /// application if the specified size does not match the extent.
123  ///
124  /// \param[in] first a valid address pointing to the first element of the
125  /// span. \param[in] last a pointer such that `[first, last)` is a valid
126  /// range.
127  ///
128  /// \pre `last - first == extent`
129  ///
130  /// \post `data() == first`
131  /// \post `size() == last - first`
132  ///
133  /// \throws Nothing.
135 
136  /// Implicit conversion from a built-in C-style array.
137  ///
138  /// \param[in] arr A native array which will be viewed on.
139  ///
140  /// \post `data() = &arr[0]`
141  /// \post `size() == extent`
142  ///
143  /// \throws Nothing.
144  constexpr span(element_type (&arr)[sextent]) noexcept // NOLINT
145  : pointer_{&arr[0]} {}
146 
147  /// Implicit conversion from const `std::array`s.
148  ///
149  /// \param[in] arr A `std::array` which will be viewed on.
150  ///
151  /// \pre `std::is_const<element_type>`
152  ///
153  /// \post `data() = arr.data()`
154  /// \post `size() == extent`
155  ///
156  /// \throws Nothing.
157  template <typename ValueType, std::size_t Extent,
158  typename = std::enable_if_t<Extent == extent>,
159  typename = std::enable_if_t<std::is_convertible<
160  const ValueType (*)[], element_type (*)[]>::value>>
161  constexpr span(const std::array<ValueType, Extent>& arr) noexcept // NOLINT
162  : pointer_{arr.data()} {}
163 
164  /// Implicit conversion from mutable `std::array`s.
165  ///
166  /// \param[in] arr A `std::array` which will be viewed on.
167  ///
168  /// \pre `M == extent`
169  ///
170  /// \post `data() = arr.data()`
171  /// \post `size() == extent`
172  ///
173  /// \throws Nothing.
174  template <typename ValueType, std::size_t Extent,
175  typename = std::enable_if_t<Extent == extent>,
176  typename = std::enable_if_t<std::is_convertible<
177  ValueType (*)[], element_type (*)[]>::value>>
178  constexpr span(std::array<ValueType, Extent>& arr) noexcept // NOLINT
179  : pointer_{arr.data()} {}
180 
181  /// Implicit conversion operator from a mutable container.
182  ///
183  /// \param[in] container A container which owns the contiguous memory. The
184  /// container must outlive this span, otherwise the span is
185  /// dangling.
186  ///
187  /// \tparam Container A container class which has the class member functions
188  /// `Container::data()` and `Container::size()`.
189  ///
190  /// \pre `container.size() == extent`
191  /// \pre `!is_span_v<Container>`
192  ///
193  /// \post `data() == container.data()`
194  /// \post `size() == container.size() == extent`
195  ///
196  /// \throws Nothing.
197 #ifdef DOXYGEN
198  template <typename Container>
199 #else
200  template <typename Container,
201  typename = std::enable_if_t<!std::is_array<Container>::value>,
202  typename = std::enable_if_t<
203  !detail::is_std_array<std::remove_const_t<Container>>::value>,
204  typename = std::enable_if_t<!is_span<Container>::value>,
205  typename = std::enable_if_t<std::is_convertible<
206  detected_t<detail::array_type_t, Container&>,
207  element_type (*)[]>::value>>
208 #endif
209  constexpr span(Container& container) // NOLINT
210  : pointer_{container.data()} {
211  FUB_ASSERT(container.size() == extent);
212  }
213 
214  /// Implicit conversion operator from a constant container.
215  ///
216  /// \param[in] container A container which owns the contiguous memory. The
217  /// container must outlive this span, otherwise the span is
218  /// dangling.
219  ///
220  /// \tparam Container A container class which has the class member functions
221  /// `Container::data()` and `Container::size()`.
222  ///
223  /// \pre `extent <= container.size()`
224  /// \pre `!is_span_v<Container>`
225  ///
226  /// \post `data() == container.data()`
227  /// \post `size() == container.size() == extent`
228  ///
229  /// \throws Nothing.
230 #ifdef DOXYGEN
231  template <typename Container>
232 #else
233  template <
234  typename Container,
235  typename = std::enable_if_t<!std::is_array<Container>::value>,
236  typename = std::enable_if_t<!detail::is_std_array<Container>::value>,
237  typename = std::enable_if_t<!is_span<Container>::value>,
238  typename = std::enable_if_t<std::is_convertible<
240  element_type (*)[]>::value>>
241 #endif
242  constexpr span(const Container& container) // NOLINT
243  : pointer_{container.data()} {
244  FUB_ASSERT(container.size() == extent);
245  }
246 
247  /// Implicit conversion from other span types.
248  ///
249  /// \tparam S the element type of the other span.
250  /// \tparam M the static extents of the other span.
251  ///
252  /// \pre s.size() == extent
253  /// \pre std::is_convertible<S(*)[], T(*)[]>::value
254  ///
255  /// \post `data() == s.data()`
256  /// \post `size() == s.size() == extent`.
257 #ifdef DOXYGEN
258  template <typename S, std::ptrdiff_t M>
259 #else
260  template <
261  typename S, std::ptrdiff_t M,
262  typename = std::enable_if_t<std::is_convertible<
263  typename span<S, M>::element_type (*)[], element_type (*)[]>::value>,
264  typename = std::enable_if_t<extent == M>>
265 #endif
266  constexpr span(const span<S, M>& s) noexcept // NOLINT
267  : pointer_{s.data()} {
268  }
269 
270  template <
271  typename S,
272  typename = std::enable_if_t<std::is_convertible<
273  typename span<S>::element_type (*)[], element_type (*)[]>::value>>
274  constexpr span(const span<S>& s) // NOLINT
275  : pointer_{s.data()} {
276  FUB_ASSERT(s.size() == extent);
277  }
278 
279  /// Defaulted copy constructor to trivially copy the class member variables.
280  ///
281  /// \throws Nothing.
282  constexpr span(const span& s) noexcept = default;
283 
284  /// \name Subviews [span.sub]
285 
286  /// Returns a span of the first `Count`-many elements of this span.
287  ///
288  /// \tparam Count Size of the returned subspan.
289  ///
290  /// \pre `0 <= Count && Count <= extent`.
291  ///
292  /// \throws Nothing.
293  template <ptrdiff_t Count,
294  typename = std::enable_if_t<(0 <= Count && Count <= extent)>>
295  constexpr span<element_type, Count> first() const {
296  return {pointer_, Count};
297  }
298 
299  /// Returns a span of the first `count`-many elements of this span.
300  ///
301  /// \param[in] count Size of the returned subspan.
302  ///
303  /// \pre `0 <= count && count <= extent`.
304  ///
305  /// \throws Nothing.
306  constexpr span<element_type> first(index_type count) const {
307  FUB_ASSERT(0 <= count && count <= size());
308  return {pointer_, count};
309  }
310 
311  /// Returns a span of the last `Count`-many elements of this span.
312  ///
313  /// \tparam Count Size of the returned subspan.
314  ///
315  /// \pre `0 <= Count && Count <= extent`.
316  ///
317  /// \throws Nothing.
318  template <ptrdiff_t Count,
319  typename = std::enable_if_t<(0 <= Count && Count <= extent)>>
320  constexpr span<element_type, Count> last() const {
321  return {pointer_ + (extent - Count), Count};
322  }
323 
324  /// Returns a span of the last `count`-many elements of this span.
325  ///
326  /// \param[in] count Size of the returned subspan.
327  ///
328  /// \pre `0 <= count && count <= extent`.
329  ///
330  /// \throws Nothing.
331  constexpr span<element_type> last(index_type count) const {
332  FUB_ASSERT(0 <= count && count <= extent);
333  return {pointer_ + (extent - count), count};
334  }
335 
336  /// Returns a subspan viewing `Count` many elements from offset `Offset`.
337  ///
338  /// \tparam Offset the offset of the returned subspan.
339  /// \tparam Count Size of the returned subspan.
340  ///
341  /// \pre `0 <= Count && Count <= extent`.
342  ///
343  /// \throws Nothing.
344  template <
345  ptrdiff_t Offset, ptrdiff_t Count = dynamic_extent,
346  typename = std::enable_if_t<(0 <= Offset && Offset <= extent)>,
347  typename = std::enable_if_t<(Count == dynamic_extent ||
348  (0 <= Count && Count + Offset <= extent))>>
349  constexpr auto subspan() const {
350 #ifndef __cpp_if_constexpr
351  struct if_constexpr_t_ {
352  auto operator()(std::true_type, pointer p) {
353  return span<T, extent - Offset>{p + Offset, extent - Offset};
354  }
355  auto operator()(std::false_type, pointer p) {
356  return span<T, Count>{p + Offset, Count};
357  }
358  } if_constexpr_{};
359  return if_constexpr_(Count == dynamic_extent, pointer_, extent);
360 #else
361  if constexpr (Count == dynamic_extent) {
362  return span<T, extent - Offset>{pointer_ + Offset, extent - Offset};
363  } else {
364  return span<T, Count>{pointer_ + Offset, Count};
365  }
366 #endif
367  }
368 
369  /// Returns a subspan viewing `count` many elements from offset `offset`.
370  ///
371  /// \param offset the offset of the returned subspan.
372  /// \param count Size of the returned subspan.
373  ///
374  /// \pre `0 <= offset && offset <= extent`.
375  /// \pre `count == dynamic_extent || 0 <= count && count + offset <= size()`.
376  ///
377  /// \throws Nothing.
378  constexpr span<element_type>
379  subspan(index_type offset, index_type count = dynamic_extent) const {
380  FUB_ASSERT(0 <= offset && offset <= size());
381  FUB_ASSERT(count == dynamic_extent ||
382  (0 <= count && count + offset <= size()));
383  return {pointer_ + offset,
384  count == dynamic_extent ? size() - offset : count};
385  }
386 
387  /// \name Observers [span.obs]
388 
389  /// Returns the number of elements in the span.
390  ///
391  /// \throws Nothing.
392  constexpr index_type size() const noexcept { return extent; }
393 
394  /// Returns the number of bytes which are spanned by this span.
395  ///
396  /// \throws Nothing.
397  constexpr index_type size_bytes() const noexcept {
398  return sizeof(T) * extent;
399  }
400 
401  /// Returns true if `size() == 0`.
402  ///
403  /// \throws Nothing.
404  constexpr bool empty() const noexcept { return false; }
405 
406  /// \name Element access [span.elem]
407 
408  /// Returns the underlying pointer.
409  ///
410  /// \throws Nothing.
411  constexpr pointer data() const noexcept { return pointer_; }
412 
413  /// Accesses the n-th element of the spanned array.
414  ///
415  /// \throws Nothing.
416  constexpr reference operator[](index_type n) const { return pointer_[n]; }
417 
418  /// Accesses the n-th element of the spanned array.
419  ///
420  /// \throws Nothing.
421  constexpr reference operator()(index_type n) const { return pointer_[n]; }
422 
423  /// \name Iterator support [span.iterators]
424 
425  /// Returns an iterator pointing to the first element of the span.
426  ///
427  /// \throws Nothing.
428  constexpr iterator begin() const noexcept { return pointer_; }
429 
430  /// Returns a const iterator pointing to the first element of the span.
431  ///
432  /// \throws Nothing.
433  constexpr const_iterator cbegin() const noexcept { return pointer_; }
434 
435  /// Returns an iterator pointing one after the last element of the span.
436  ///
437  /// \throws Nothing.
438  constexpr iterator end() const noexcept { return pointer_ + extent; }
439 
440  /// Returns a const iterator pointing one after the last element of the span.
441  ///
442  /// \throws Nothing.
443  constexpr const_iterator cend() const noexcept { return pointer_ + extent; }
444 
445  /// Returns a reverse iterator pointing to the last element of the span.
446  ///
447  /// \throws Nothing.
448  constexpr reverse_iterator rbegin() const noexcept {
449  return reverse_iterator(end());
450  }
451 
452  /// Returns a const reverse iterator pointing to the last element of the span.
453  ///
454  /// \throws Nothing.
455  constexpr const_reverse_iterator crbegin() const noexcept {
456  return const_reverse_iterator(cend());
457  }
458 
459  /// Returns a reverse iterator pointing to the first element of the span.
460  ///
461  /// \throws Nothing.
462  constexpr reverse_iterator rend() const noexcept {
463  return reverse_iterator(begin());
464  }
465 
466  /// Returns a const reverse iterator pointing to the first element of the
467  /// span.
468  ///
469  /// \throws Nothing.
470  constexpr const_reverse_iterator crend() const noexcept {
471  return const_reverse_iterator(cbegin());
472  }
473 
474 private:
476 };
477 
478 /// \ingroup spans
479 /// A span is a view over a contiguous sequence of objects, the storage of which
480 /// is owned by some other object.
481 ///
482 /// All member functions of span have constant time complexity.
483 ///
484 /// `T` is required to be a complete object type that is not an abstract
485 /// class type.
486 ///
487 /// If `N` is negative and not equal to dynamic_­extent, the program is
488 /// ill-formed.
489 template <typename T> class span<T, 0> {
490 public:
491  using element_type = T;
492  using pointer = T*;
493  using reference = T&;
494  using value_type = std::remove_cv_t<T>;
495  using index_type = std::ptrdiff_t;
496  using difference_type = std::ptrdiff_t;
497  using iterator = pointer;
498  using const_iterator = std::add_const_t<T>*;
499  using reverse_iterator = std::reverse_iterator<iterator>;
500  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
501 
502  static constexpr index_type extent = 0;
503 
504  /// \name Constructors, copy, and assignment [span.cons]
505 
506  /// Constructs an empty span.
507  ///
508  /// \post `data() == nullptr`
509  /// \post `size() == 0`
510  ///
511  /// \throws Nothing.
512  constexpr span() noexcept = default;
513 
514  /// Constructs a span from a `pointer` + `size` pair.
515  ///
516  /// This performs an assertion check in debug builds which will terminate the
517  /// application if the specified size does not match the extent.
518  ///
519  /// \pre `p` is a valid pointer.
520  /// \pre `size == 0`
521  ///
522  /// \post `data() == p`
523  /// \post `size() == 0`
524  ///
525  /// \throws Nothing.
526  constexpr span(pointer p, [[maybe_unused]] index_type size) : pointer_{p} {
527  FUB_ASSERT(size == 0);
528  }
529 
530  /// Constructs a span from two `pointer`s.
531  ///
532  /// This performs an assertion check in debug builds which will terminate the
533  /// application if the specified size does not match the extent.
534  ///
535  /// \pre `first` and `last` are valid pointers.
536  /// \pre `first == last`
537  ///
538  /// \post `data() == first`
539  /// \post `size() == last - first`
540  ///
541  /// \throws Nothing.
542  constexpr span(pointer first, pointer last) : span(first, last - first) {}
543 
544  /// Implicit conversion operator from a mutable container.
545  ///
546  /// \pre `container.size() == extent`
547  /// \pre `!is_span_v<Container>`
548  /// \pre `container.size() == 0`
549  ///
550  /// \post `data() == container.data()`
551  /// \post `size() == container.size()`
552  ///
553  /// \throws Nothing.
554 #ifdef DOXYGEN
555  template <typename Container>
556 #else
557  template <typename Container,
558  typename = std::enable_if_t<!std::is_array<Container>::value>,
559  typename = std::enable_if_t<!is_span<Container>::value>,
560  typename = std::enable_if_t<
561  std::is_convertible<detected_t<detail::array_type_t, Container>,
562  element_type (*)[]>::value>>
563 #endif
564  constexpr span(Container& container) // NOLINT
565  : pointer_{container.data()} {
566  FUB_ASSERT(container.size() == extent);
567  }
568 
569 /// Implicit conversion operator from a constant container.
570 ///
571 /// \pre `extent <= container.size()`
572 /// \pre `!is_span_v<Container>`
573 /// \pre `container.size() == 0`
574 ///
575 /// \post `data() == container.data()`
576 /// \post `size() == container.size()`
577 ///
578 /// \throws Nothing.
579 #ifdef DOXYGEN
580  template <typename Container>
581 #else
582  template <typename Container,
583  typename = std::enable_if_t<!std::is_array<Container>::value>,
584  typename = std::enable_if_t<!is_span<Container>::value>,
585  typename = std::enable_if_t<
586  std::is_convertible<detected_t<detail::array_type_t, Container>,
587  element_type (*)[]>::value>>
588 #endif
589  constexpr span(const Container& container) // NOLINT
590  : pointer_{container.data()} {
591  FUB_ASSERT(container.size() == extent);
592  }
593 
594  /// Implicit conversion from other span types.
595  ///
596  /// \pre std::is_convertible<S(*)[], T(*)[]>::value
597  ///
598  /// \post data() == s.data()
599  ///
600  /// \throws Nothing.
601 #ifdef DOXYGEN
602  template <typename S>
603 #else
604  template <
605  typename S,
606  typename = std::enable_if_t<std::is_convertible<
607  typename span<S, 0>::element_type (*)[], element_type (*)[]>::value>>
608 #endif
609  constexpr span(const span<S, 0>& s) noexcept // NOLINT
610  : pointer_{s.data()} {
611  }
612 
613  /// Defaulted copy constructor to trivially copy the class member variables.
614  ///
615  /// \throws Nothing.
616  constexpr span(const span& s) noexcept = default;
617 
618  /// \name Observers [span.obs]
619 
620  /// Returns the number of elements in the span.
621  ///
622  /// \throws Nothing.
623  constexpr index_type size() const noexcept { return 0; }
624 
625  /// Returns the number of bytes which are spanned by this span.
626  ///
627  /// \throws Nothing.
628  constexpr std::ptrdiff_t size_bytes() const noexcept { return 0; }
629 
630  /// Returns true if `size() == 0`.
631  ///
632  /// \throws Nothing.
633  constexpr bool empty() const noexcept { return true; }
634 
635  /// \name Element access [span.elem]
636 
637  /// Returns the underlying pointer.
638  ///
639  /// \throws Nothing.
640  constexpr pointer data() const noexcept { return pointer_; }
641 
642  /// \name Iterator support [span.iterators]
643 
644  /// Returns an iterator pointing to the first element of the span.
645  ///
646  /// \throws Nothing.
647  constexpr iterator begin() const noexcept { return data(); }
648 
649  /// Returns a const iterator pointing to the first element of the span.
650  ///
651  /// \throws Nothing.
652  constexpr const_iterator cbegin() const noexcept { return data(); }
653 
654  /// Returns an iterator pointing one after the last element of the span.
655  ///
656  /// \throws Nothing.
657  constexpr iterator end() const noexcept { return begin() + size(); }
658 
659  /// Returns a const iterator pointing one after the last element of the span.
660  ///
661  /// \throws Nothing.
662  constexpr const_iterator cend() const noexcept { return begin() + size(); }
663 
664  /// Returns a reverse iterator pointing to the last element of the span.
665  ///
666  /// \throws Nothing.
667  constexpr reverse_iterator rbegin() const noexcept {
668  return reverse_iterator(end());
669  }
670 
671  /// Returns a const reverse iterator pointing to the last element of the span.
672  ///
673  /// \throws Nothing.
674  constexpr const_reverse_iterator crbegin() const noexcept {
675  return const_reverse_iterator(cend());
676  }
677 
678  /// Returns a reverse iterator pointing to the first element of the span.
679  ///
680  /// \throws Nothing.
681  constexpr reverse_iterator rend() const noexcept {
682  return reverse_iterator(begin());
683  }
684 
685  /// Returns a const reverse iterator pointing to the first element of the
686  /// span.
687  ///
688  /// \throws Nothing.
689  constexpr const_reverse_iterator crend() const noexcept {
690  return const_reverse_iterator(cbegin());
691  }
692 
693 private:
694  pointer pointer_{nullptr};
695 };
696 
697 /// \ingroup spans
698 /// span is a compact view over a contiguous range of data.
699 ///
700 /// This class models something like
701 ///
702 /// \code struct span { pointer ptr; std::ptrdiff_t length; }; \endcode
703 ///
704 /// Where the `length` can be omitted for statically sized views.
705 template <typename T> class span<T, dynamic_extent> {
706 public:
707  using element_type = T;
708  using pointer = T*;
709  using reference = T&;
710  using value_type = std::remove_cv_t<T>;
711  using index_type = std::ptrdiff_t;
712  using difference_type = std::ptrdiff_t;
713  using iterator = pointer;
714  using const_iterator = std::add_const_t<T>*;
715  using reverse_iterator = std::reverse_iterator<iterator>;
716  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
717 
718  static constexpr index_type extent = dynamic_extent;
719 
720  /////////////////////////////////////////////////////////////////////////////
721  // Constructors
722 
723  /// Constructs an empty span of size 0.
724  ///
725  /// This initializes the underlying pointer to nullptr and the size to 0.
726  ///
727  /// \throws Nothing.
728  ///
729  /// \post data() == nullptr
730  /// \post size() == 0
731  constexpr span() = default;
732 
733  /// Constructs a span from a `pointer` + `size` pair.
734  ///
735  /// This performs an assertion check in debug builds which will terminate the
736  /// application if the specified size does not match the extent.
737  ///
738  /// \throws Nothing.
739  ///
740  /// \post data() == p
741  /// \post size() == size
742  constexpr span(pointer p, index_type size) noexcept
743  : pointer_{p}, size_{size} {}
744 
745  /// Constructs a span from two `pointer`s.
746  ///
747  /// This performs an assertion check in debug builds which will terminate the
748  /// application if the specified size does not match the extent.
749  ///
750  /// \throws Nothing.
751  ///
752  /// \post data() == first
753  /// \post size() == last - first
754  constexpr span(pointer first, pointer last) noexcept
755  : pointer_{first}, size_{last - first} {}
756 
757  /// Implicit conversion from a built-in C-style array.
758  ///
759  /// \throws Nothing.
760  ///
761  /// \post data() = pointer(&arr[0])
762  /// \post size() == M
763  template <std::size_t M>
764  constexpr span(element_type (&arr)[M]) noexcept // NOLINT
765  : pointer_{&arr[0]}, size_{static_cast<index_type>(M)} {}
766 
767  /// Implicit conversion from mutable Container-like types.
768  ///
769  /// \pre S(*)[] is convertible to element_type(*)[]
770  ///
771  /// \throws Nothing.
772  ///
773  /// \post data() = container.data()
774  /// \post size() = container.size()
775  template <
776  typename Container,
777  typename = std::enable_if_t<!std::is_array<Container>::value>,
778  typename =
779  std::enable_if_t<!is_span<std::remove_const_t<Container>>::value>,
780  typename = std::enable_if_t<
781  std::is_convertible<detected_t<detail::array_type_t, Container&>,
782  element_type (*)[]>::value>>
783  constexpr span(Container& container) noexcept // NOLINT
784  : pointer_{container.data()}, size_{static_cast<index_type>(
785  container.size())} {}
786 
787  /// Implicit conversion from other span types.
788  ///
789  /// \pre size() <= M
790  /// \pre std::is_convertible<S(*)[], T(*)[]>::value
791  ///
792  /// \post data() == s.data()
793  template <
794  typename S, index_type OtherExtents,
795  typename = std::enable_if_t<std::is_convertible<S (*)[], T (*)[]>::value>>
796  constexpr span(const span<S, OtherExtents>& s) noexcept // NOLINT
797  : pointer_{s.data()}, size_{s.size()} {}
798 
799  constexpr span(const span& s) noexcept = default;
800 
801  /// \name Subviews [span.sub]
802 
803  /// Returns a span of the first `Count`-many elements of this span.
804  ///
805  /// \tparam Count Size of the returned subspan.
806  ///
807  /// \pre `0 <= Count && Count <= extent`.
808  ///
809  /// \throws Nothing.
810  template <ptrdiff_t Count, typename = std::enable_if_t<0 <= Count>>
811  constexpr span<element_type, Count> first() const {
812  FUB_ASSERT(Count <= size());
813  return {pointer_, Count};
814  }
815 
816  /// Returns a span of the first `count`-many elements of this span.
817  ///
818  /// \param[in] count Size of the returned subspan.
819  ///
820  /// \pre `0 <= count && count <= extent`.
821  ///
822  /// \throws Nothing.
823  constexpr span<element_type> first(index_type count) const {
824  FUB_ASSERT(0 <= count && count <= size());
825  return {pointer_, count};
826  }
827 
828  /// Returns a span of the last `Count`-many elements of this span.
829  ///
830  /// \tparam Count Size of the returned subspan.
831  ///
832  /// \pre `0 <= Count && Count <= extent`.
833  ///
834  /// \throws Nothing.
835  template <ptrdiff_t Count, typename = std::enable_if_t<0 <= Count>>
836  constexpr span<element_type, Count> last() const {
837  FUB_ASSERT(Count <= size());
838  return {pointer_ + (size() - Count), Count};
839  }
840 
841  /// Returns a span of the last `count`-many elements of this span.
842  ///
843  /// \param[in] count Size of the returned subspan.
844  ///
845  /// \pre `0 <= count && count <= extent`.
846  ///
847  /// \throws Nothing.
848  constexpr span<element_type> last(index_type count) const {
849  FUB_ASSERT(0 <= count && count <= size());
850  return {pointer_ + (extent - count), count};
851  }
852 
853  /// Returns a subspan viewing `Count` many elements from offset `Offset`.
854  ///
855  /// \tparam Offset the offset of the returned subspan.
856  /// \tparam Count Size of the returned subspan.
857  ///
858  /// \pre `0 <= Count && Count <= extent`.
859  ///
860  /// \throws Nothing.
861  template <ptrdiff_t Offset, ptrdiff_t Count = dynamic_extent,
862  typename = std::enable_if_t<0 <= Offset>>
863  constexpr span<element_type, Count> subspan() const {
864  FUB_ASSERT(Offset <= size());
865  FUB_ASSERT(Count == dynamic_extent ||
866  (0 <= Count && Count + Offset <= size()));
867  return {pointer_ + Offset,
868  Count == dynamic_extent ? size() - Offset : Count};
869  }
870 
871  /// Returns a subspan viewing `count` many elements from offset `offset`.
872  ///
873  /// \param offset the offset of the returned subspan.
874  /// \param count Size of the returned subspan.
875  ///
876  /// \pre `0 <= offset && offset <= extent`.
877  /// \pre `count == dynamic_extent || 0 <= count && count + offset <= size()`.
878  ///
879  /// \throws Nothing.
880  constexpr span<element_type>
881  subspan(index_type offset, index_type count = dynamic_extent) const {
882  FUB_ASSERT(0 <= offset && offset <= size());
883  FUB_ASSERT(count == dynamic_extent ||
884  (0 <= count && count + offset <= size()));
885  return {pointer_ + offset,
886  count == dynamic_extent ? size() - offset : count};
887  }
888 
889  /// \name Observers [span.obs]
890 
891  /// Returns the number of elements in the span.
892  ///
893  /// \throws Nothing.
894  constexpr index_type size() const noexcept { return size_; }
895 
896  /// Returns the number of bytes which are spanned by this span.
897  ///
898  /// \throws Nothing.
899  constexpr index_type size_bytes() const noexcept { return sizeof(T) * size_; }
900 
901  /// Returns true if `size() == 0`.
902  ///
903  /// \throws Nothing.
904  constexpr bool empty() const noexcept { return size_ == 0; }
905 
906  /// \name Element access [span.elem]
907 
908  /// Returns the underlying pointer.
909  ///
910  /// \throws Nothing.
911  constexpr pointer data() const noexcept { return pointer_; }
912 
913  /// Accesses the n-th element of the spanned array.
914  ///
915  /// \throws Nothing.
916  constexpr reference operator[](index_type n) const { return pointer_[n]; }
917 
918  /// Accesses the n-th element of the spanned array.
919  ///
920  /// \throws Nothing.
921  constexpr reference operator()(index_type n) const { return pointer_[n]; }
922 
923  /// \name Iterator support [span.iterators]
924 
925  /// Returns an iterator pointing to the first element of the span.
926  ///
927  /// \throws Nothing.
928  constexpr iterator begin() const noexcept { return pointer_; }
929 
930  /// Returns a const iterator pointing to the first element of the span.
931  ///
932  /// \throws Nothing.
933  constexpr const_iterator cbegin() const noexcept { return pointer_; }
934 
935  /// Returns an iterator pointing one after the last element of the span.
936  ///
937  /// \throws Nothing.
938  constexpr iterator end() const noexcept { return pointer_ + size_; }
939 
940  /// Returns a const iterator pointing one after the last element of the span.
941  ///
942  /// \throws Nothing.
943  constexpr const_iterator cend() const noexcept { return pointer_ + size_; }
944 
945  /// Returns a reverse iterator pointing to the last element of the span.
946  ///
947  /// \throws Nothing.
948  constexpr reverse_iterator rbegin() const noexcept {
949  return reverse_iterator(end());
950  }
951 
952  /// Returns a const reverse iterator pointing to the last element of the span.
953  ///
954  /// \throws Nothing.
955  constexpr const_reverse_iterator crbegin() const noexcept {
956  return const_reverse_iterator(cend());
957  }
958 
959  /// Returns a reverse iterator pointing to the first element of the span.
960  ///
961  /// \throws Nothing.
962  constexpr reverse_iterator rend() const noexcept {
963  return reverse_iterator(begin());
964  }
965 
966  /// Returns a const reverse iterator pointing to the first element of the
967  /// span.
968  ///
969  /// \throws Nothing.
970  constexpr const_reverse_iterator crend() const noexcept {
971  return const_reverse_iterator(cbegin());
972  }
973 
974 private:
975  pointer pointer_{nullptr};
976  index_type size_{0};
977 };
978 
979 //#ifdef __cpp_deduction_guides
980 
981 template <class T, typename I> span(T*, I)->span<T>;
982 
983 template <class T, size_t N>
984 span(T (&)[N])->span<T, static_cast<std::ptrdiff_t>(N)>;
985 
986 template <class T, size_t N>
987 span(std::array<T, N>&)->span<T, static_cast<std::ptrdiff_t>(N)>;
988 
989 template <class T, size_t N>
990 span(const std::array<T, N>&)->span<const T, static_cast<std::ptrdiff_t>(N)>;
991 
992 template <class Container>
993 span(Container&)->span<typename Container::value_type>;
994 
995 template <class Container>
996 span(const Container&)->span<const typename Container::value_type>;
997 
998 //#endif
999 
1000 template <class T, size_t N>
1002  return span<T, static_cast<std::ptrdiff_t>(N)>(array);
1003 }
1004 
1005 template <class T, size_t N>
1006 auto make_span(std::array<T, N>& array)
1008  return span<T, static_cast<std::ptrdiff_t>(N)>(array);
1009 }
1010 
1011 template <class T, size_t N>
1012 auto make_span(const std::array<T, N>& array)
1015 }
1016 
1017 template <class Container>
1020 }
1021 
1022 template <class Container>
1023 auto make_span(const Container& array)
1026 }
1027 
1028 } // namespace fub
1029 
1030 namespace std {
1031 
1032 template <typename T, std::ptrdiff_t N>
1033 class tuple_size<fub::span<T, N>>
1034  : public std::integral_constant<std::size_t, static_cast<std::size_t>(N)> {
1035 };
1036 
1037 } // namespace std
1038 
1039 #endif // !SPAN_HPP
#define FUB_ASSERT(x)
Definition: assert.hpp:39
A span is a view over a contiguous sequence of objects, the storage of which is owned by some other o...
Definition: span.hpp:489
constexpr std::ptrdiff_t size_bytes() const noexcept
Returns the number of bytes which are spanned by this span.
Definition: span.hpp:628
constexpr const_reverse_iterator crbegin() const noexcept
Returns a const reverse iterator pointing to the last element of the span.
Definition: span.hpp:674
constexpr span(pointer first, pointer last)
Constructs a span from two pointers.
Definition: span.hpp:542
constexpr span() noexcept=default
Constructs an empty span.
constexpr const_iterator cend() const noexcept
Returns a const iterator pointing one after the last element of the span.
Definition: span.hpp:662
T & reference
Definition: span.hpp:493
constexpr span(const span< S, 0 > &s) noexcept
Implicit conversion from other span types.
Definition: span.hpp:609
constexpr reverse_iterator rbegin() const noexcept
Returns a reverse iterator pointing to the last element of the span.
Definition: span.hpp:667
constexpr span(const span &s) noexcept=default
Defaulted copy constructor to trivially copy the class member variables.
constexpr iterator end() const noexcept
Returns an iterator pointing one after the last element of the span.
Definition: span.hpp:657
pointer iterator
Definition: span.hpp:497
std::ptrdiff_t index_type
Definition: span.hpp:495
constexpr bool empty() const noexcept
Returns true if size() == 0.
Definition: span.hpp:633
constexpr pointer data() const noexcept
Returns the underlying pointer.
Definition: span.hpp:640
std::remove_cv_t< T > value_type
Definition: span.hpp:494
T element_type
Definition: span.hpp:491
constexpr iterator begin() const noexcept
Returns an iterator pointing to the first element of the span.
Definition: span.hpp:647
std::ptrdiff_t difference_type
Definition: span.hpp:496
std::add_const_t< T > * const_iterator
Definition: span.hpp:498
constexpr span(Container &container)
Implicit conversion operator from a mutable container.
Definition: span.hpp:564
T * pointer
Definition: span.hpp:492
constexpr span(const Container &container)
Implicit conversion operator from a constant container.
Definition: span.hpp:589
constexpr reverse_iterator rend() const noexcept
Returns a reverse iterator pointing to the first element of the span.
Definition: span.hpp:681
constexpr const_reverse_iterator crend() const noexcept
Returns a const reverse iterator pointing to the first element of the span.
Definition: span.hpp:689
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition: span.hpp:500
constexpr index_type size() const noexcept
Returns the number of elements in the span.
Definition: span.hpp:623
std::reverse_iterator< iterator > reverse_iterator
Definition: span.hpp:499
constexpr const_iterator cbegin() const noexcept
Returns a const iterator pointing to the first element of the span.
Definition: span.hpp:652
std::reverse_iterator< iterator > reverse_iterator
Definition: span.hpp:715
constexpr span(Container &container) noexcept
Implicit conversion from mutable Container-like types.
Definition: span.hpp:783
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition: span.hpp:716
std::ptrdiff_t difference_type
Definition: span.hpp:712
constexpr span(pointer p, index_type size) noexcept
Constructs a span from a pointer + size pair.
Definition: span.hpp:742
constexpr span(pointer first, pointer last) noexcept
Constructs a span from two pointers.
Definition: span.hpp:754
constexpr span(element_type(&arr)[M]) noexcept
Implicit conversion from a built-in C-style array.
Definition: span.hpp:764
std::remove_cv_t< T > value_type
Definition: span.hpp:710
T * pointer
Definition: span.hpp:708
std::ptrdiff_t index_type
Definition: span.hpp:711
T element_type
Definition: span.hpp:707
std::add_const_t< T > * const_iterator
Definition: span.hpp:714
constexpr span(const span &s) noexcept=default
T & reference
Definition: span.hpp:709
pointer iterator
Definition: span.hpp:713
constexpr span()=default
Constructs an empty span of size 0.
constexpr span(const span< S, OtherExtents > &s) noexcept
Implicit conversion from other span types.
Definition: span.hpp:796
A span is a view over a contiguous sequence of objects, the storage of which is owned by some other o...
Definition: span.hpp:81
constexpr const_reverse_iterator crbegin() const noexcept
Returns a const reverse iterator pointing to the last element of the span.
Definition: span.hpp:455
constexpr span< element_type > subspan(index_type offset, index_type count=dynamic_extent) const
Returns a subspan viewing count many elements from offset offset.
Definition: span.hpp:379
pointer pointer_
Returns an iterator pointing to the first element of the span.
Definition: span.hpp:475
constexpr auto subspan() const
Returns a subspan viewing Count many elements from offset Offset.
Definition: span.hpp:349
constexpr reverse_iterator rbegin() const noexcept
Returns a reverse iterator pointing to the last element of the span.
Definition: span.hpp:448
constexpr span(pointer first, pointer last)
Constructs a span from two pointers.
Definition: span.hpp:134
static constexpr std::size_t sextent
Definition: span.hpp:97
std::ptrdiff_t index_type
Definition: span.hpp:89
T & reference
Definition: span.hpp:87
constexpr reference operator()(index_type n) const
Accesses the n-th element of the spanned array.
Definition: span.hpp:421
static constexpr index_type extent
Definition: span.hpp:96
constexpr index_type size() const noexcept
Returns the number of elements in the span.
Definition: span.hpp:392
constexpr index_type size_bytes() const noexcept
Returns the number of bytes which are spanned by this span.
Definition: span.hpp:397
std::add_const_t< T > * const_iterator
Definition: span.hpp:92
constexpr span(std::array< ValueType, Extent > &arr) noexcept
Implicit conversion from mutable std::arrays.
Definition: span.hpp:178
constexpr reverse_iterator rend() const noexcept
Returns a reverse iterator pointing to the first element of the span.
Definition: span.hpp:462
std::ptrdiff_t difference_type
Definition: span.hpp:90
constexpr const_iterator cend() const noexcept
Returns a const iterator pointing one after the last element of the span.
Definition: span.hpp:443
pointer iterator
Definition: span.hpp:91
T * pointer
Definition: span.hpp:86
constexpr span(const span &s) noexcept=default
Defaulted copy constructor to trivially copy the class member variables.
constexpr iterator begin() const noexcept
Returns an iterator pointing to the first element of the span.
Definition: span.hpp:428
constexpr reference operator[](index_type n) const
Accesses the n-th element of the spanned array.
Definition: span.hpp:416
constexpr span< element_type, Count > last() const
Returns a span of the last Count-many elements of this span.
Definition: span.hpp:320
constexpr iterator end() const noexcept
Returns an iterator pointing one after the last element of the span.
Definition: span.hpp:438
constexpr span(const Container &container)
Implicit conversion operator from a constant container.
Definition: span.hpp:242
constexpr const_iterator cbegin() const noexcept
Returns a const iterator pointing to the first element of the span.
Definition: span.hpp:433
constexpr span(const std::array< ValueType, Extent > &arr) noexcept
Implicit conversion from const std::arrays.
Definition: span.hpp:161
std::reverse_iterator< iterator > reverse_iterator
Definition: span.hpp:93
constexpr span(const span< S, M > &s) noexcept
Implicit conversion from other span types.
Definition: span.hpp:266
constexpr span(const span< S > &s)
Constructs a span from a pointer and size pair.
Definition: span.hpp:274
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition: span.hpp:94
constexpr bool empty() const noexcept
Returns true if size() == 0.
Definition: span.hpp:404
constexpr span< element_type > last(index_type count) const
Returns a span of the last count-many elements of this span.
Definition: span.hpp:331
constexpr span(pointer p, [[maybe_unused]] index_type size)
Constructs a span from a pointer and size pair.
Definition: span.hpp:115
constexpr const_reverse_iterator crend() const noexcept
Returns a const reverse iterator pointing to the first element of the span.
Definition: span.hpp:470
std::remove_cv_t< T > value_type
Definition: span.hpp:88
constexpr span< element_type, Count > first() const
Returns a span of the first Count-many elements of this span.
Definition: span.hpp:295
constexpr span(Container &container)
Implicit conversion operator from a mutable container.
Definition: span.hpp:209
T element_type
Definition: span.hpp:85
constexpr span< element_type > first(index_type count) const
Returns a span of the first count-many elements of this span.
Definition: span.hpp:306
constexpr span(element_type(&arr)[sextent]) noexcept
Implicit conversion from a built-in C-style array.
Definition: span.hpp:144
constexpr pointer data() const noexcept
Returns the underlying pointer.
Definition: span.hpp:411
detail::detected_t< Op, Args... > detected_t
Returns the type of Op<Args...> or nonesuch
Definition: type_traits.hpp:97
The fub namespace.
Definition: AnyBoundaryCondition.hpp:31
span(T *, I) -> span< T >
auto make_span(T(&array)[N]) -> span< T, static_cast< std::ptrdiff_t >(N)>
Definition: span.hpp:1001
std::ptrdiff_t Extent(const PatchDataView< T, R, L > &pdv)
Definition: StateRow.hpp:127
static constexpr std::ptrdiff_t dynamic_extent
This is a magic value to denote runtime-known extents.
Definition: dynamic_extent.hpp:28
static constexpr bool is_span_v
Returns true if the specified T is a span<S, N> for some type S and integer N.
Definition: span.hpp:65
Returns true if the specified T is a span<S, N> for some type S and integer N.
Definition: span.hpp:56
This file adds basic type traits utilities which are not yet implemented in all standard libraries.