Finite Volume Solver  prototype
A framework to build finite volume solvers for the AG Klein at the Freie Universität Berlin.
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.