Backport
span.hpp
Go to the documentation of this file.
1 
7 /*
8  The MIT License (MIT)
9 
10  Copyright (c) 2020 Matthew Rodusek All rights reserved.
11 
12  Permission is hereby granted, free of charge, to any person obtaining a copy
13  of this software and associated documentation files (the "Software"), to deal
14  in the Software without restriction, including without limitation the rights
15  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16  copies of the Software, and to permit persons to whom the Software is
17  furnished to do so, subject to the following conditions:
18 
19  The above copyright notice and this permission notice shall be included in
20  all copies or substantial portions of the Software.
21 
22  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28  SOFTWARE.
29 */
30 #ifndef BPSTD_SPAN_HPP
31 #define BPSTD_SPAN_HPP
32 
33 #include "detail/config.hpp"
34 #include "detail/proxy_iterator.hpp"
35 
36 #include "cstddef.hpp" // byte
37 #include "memory.hpp" // to_address
38 #include "type_traits.hpp" // conjunction, remove_cvref_t, etc
39 
40 #include <cstddef> // std::size_t
41 #include <array> // std::array
42 #include <iterator> // std::iterator_traits
43 
44 BPSTD_COMPILER_DIAGNOSTIC_PREAMBLE
45 
46 namespace bpstd {
47 
48  //============================================================================
49  // constants : dynamic_extent
50  //============================================================================
51 
52  BPSTD_CPP17_INLINE constexpr auto dynamic_extent = static_cast<std::size_t>(-1);
53 
54  namespace detail {
55 
56  template <std::size_t Extent>
57  class extent_storage
58  {
59  public:
60  constexpr extent_storage() noexcept = default;
61 
62  template <std::size_t UExtent>
63  constexpr explicit extent_storage(extent_storage<UExtent>)
64  {
65  static_assert(
66  UExtent == Extent,
67  "Extent must be the same size as UExtent"
68  );
69  }
70 
71  constexpr explicit extent_storage(std::size_t)
72  {
73 
74  }
75 
76  constexpr std::size_t size() const noexcept
77  {
78  return Extent;
79  }
80  };
81 
82  template <>
83  class extent_storage<dynamic_extent>
84  {
85  public:
86  template <std::size_t Extent>
87  constexpr explicit extent_storage(extent_storage<Extent> ext)
88  : m_size{ext.size()}
89  {
90 
91  }
92 
93  constexpr explicit extent_storage(std::size_t size)
94  : m_size{size}
95  {
96 
97  }
98 
99  constexpr std::size_t size() const noexcept
100  {
101  return m_size;
102  }
103 
104  private:
105 
106  std::size_t m_size;
107  };
108 
109  template <typename T, std::size_t Extent>
110  class span_storage_type : public extent_storage<Extent>
111  {
112  //------------------------------------------------------------------------
113  // Constructors
114  //------------------------------------------------------------------------
115  public:
116 
117  template <typename ExtentType>
118  constexpr span_storage_type(T* data, ExtentType ext)
119  : extent_storage<Extent>(ext),
120  m_data{data}
121  {
122 
123  }
124 
125  //------------------------------------------------------------------------
126  // Observers
127  //------------------------------------------------------------------------
128  public:
129 
130  using extent_storage<Extent>::size;
131 
132  constexpr T* data() const noexcept { return m_data; }
133 
134  //------------------------------------------------------------------------
135  // Private Members
136  //------------------------------------------------------------------------
137  private:
138 
139  T* m_data;
140  };
141 
142  template <std::size_t From, std::size_t To>
143  struct is_allowed_extent_conversion
144  : bool_constant<(From == To) || (To == dynamic_extent)>{};
145 
146  template <std::size_t Extent, std::size_t Offset, std::size_t Count>
147  struct compute_subspan_size
148  : integral_constant<std::size_t,
149  (Count != dynamic_extent)
150  ? Count
151  : ((Extent != dynamic_extent) ? (Extent - Offset) : Extent)
152  >{};
153 
154  template <typename It>
155  using iter_reference = typename std::iterator_traits<It>::reference;
156 
157  template <typename It, typename T>
158  using is_iter_convertible = conjunction<
159  is_same<remove_cvref_t<iter_reference<It>>,remove_cv_t<T>>,
160  is_convertible<iter_reference<It>,remove_cv_t<T>>
161  >;
162 
163  } // namespace detail
164 
165  //============================================================================
166  // class : span
167  //============================================================================
168 
181  template <typename T, std::size_t Extent = dynamic_extent>
182  class span
183  {
184  //--------------------------------------------------------------------------
185  // Public Member Types
186  //--------------------------------------------------------------------------
187  public:
188 
189  using element_type = T;
190  using value_type = remove_cv_t<T>;
191  using size_type = std::size_t;
192  using difference_type = std::ptrdiff_t;
193 
194  using pointer = element_type*;
195  using const_pointer = const element_type*;
196  using reference = element_type&;
197  using const_reference = const element_type&;
198 
199  using iterator = detail::proxy_iterator<T*,detail::span_storage_type<T,Extent>>;
200  using reverse_iterator = std::reverse_iterator<iterator>;
201 
202  //--------------------------------------------------------------------------
203  // Public Member Constants
204  //--------------------------------------------------------------------------
205  public:
206 
207  BPSTD_CPP17_INLINE static constexpr std::size_t extent = Extent;
208 
209  //--------------------------------------------------------------------------
210  // Constructors / Assignment
211  //--------------------------------------------------------------------------
212  public:
213 
218  template <std::size_t UExtent = Extent,
219  typename = enable_if_t<detail::is_allowed_extent_conversion<0,UExtent>::value>>
220  constexpr span() noexcept;
221 
234  template <typename It,
235  enable_if_t<(Extent == bpstd::dynamic_extent) &&
237  constexpr span(It it, size_type count) noexcept;
238  template <typename It,
239  enable_if_t<(Extent != bpstd::dynamic_extent) &&
241  constexpr explicit span(It it, size_type count) noexcept;
243 
253  template <typename It, typename End,
254  enable_if_t<(Extent == bpstd::dynamic_extent) &&
256  constexpr span(It it, End end) noexcept;
257  template <typename It, typename End,
258  enable_if_t<(Extent != bpstd::dynamic_extent) &&
260  constexpr explicit span(It it, End end) noexcept;
261 
270  template <std::size_t N,
271  typename = enable_if_t<detail::is_allowed_extent_conversion<N,Extent>::value>>
272  // cppcheck-suppress noExplicitConstructor
273  constexpr span(element_type (&arr)[N]) noexcept;
274 
284  template <typename U, std::size_t N,
285  typename = enable_if_t<detail::is_allowed_extent_conversion<N,Extent>::value>>
286  // cppcheck-suppress noExplicitConstructor
287  constexpr span(std::array<U, N>& arr) noexcept;
288  template <typename U, std::size_t N,
289  typename = enable_if_t<detail::is_allowed_extent_conversion<N,Extent>::value>>
290  // cppcheck-suppress noExplicitConstructor
291  constexpr span(const std::array<U, N>& arr) noexcept;
293 
294  // range-constructor omitted since ranges are not part of backport yet
295 
304  template <typename U, std::size_t N,
305  typename = enable_if_t<detail::is_allowed_extent_conversion<N,Extent>::value>>
306  // cppcheck-suppress noExplicitConstructor
307  constexpr span(const span<U, N>& s) noexcept;
308 
312  constexpr span(const span& other) noexcept = default;
313 
314  //--------------------------------------------------------------------------
315 
320  BPSTD_CPP14_CONSTEXPR span& operator=(const span& other) noexcept = default;
321 
322  //--------------------------------------------------------------------------
323  // Element Access
324  //--------------------------------------------------------------------------
325  public:
326 
331  constexpr reference front() const noexcept;
332 
337  constexpr reference back() const noexcept;
338 
344  constexpr reference operator[](size_type idx) const noexcept;
345 
349  constexpr pointer data() const noexcept;
350 
351  //--------------------------------------------------------------------------
352  // Observers
353  //--------------------------------------------------------------------------
354  public:
355 
359  constexpr size_type size() const noexcept;
360 
364  constexpr size_type size_bytes() const noexcept;
365 
369  constexpr bool empty() const noexcept;
370 
371  //--------------------------------------------------------------------------
372  // Subviews
373  //--------------------------------------------------------------------------
374  public:
375 
382  template <std::size_t Count>
383  constexpr span<element_type, Count> first() const;
384 
391  constexpr span<element_type> first(size_t count) const;
392 
393  //--------------------------------------------------------------------------
394 
401  template <std::size_t Count>
402  constexpr span<element_type, Count> last() const;
403 
410  constexpr span<element_type> last(size_t count) const;
411 
412  //--------------------------------------------------------------------------
413 
420  template <std::size_t Offset, std::size_t Count = dynamic_extent>
422  subspan() const;
423 
430  constexpr span<element_type> subspan(std::size_t offset,
431  std::size_t count = dynamic_extent) const;
432 
433  //--------------------------------------------------------------------------
434  // Iterators
435  //--------------------------------------------------------------------------
436  public:
437 
438  constexpr iterator begin() const noexcept;
439  constexpr iterator end() const noexcept;
440  constexpr reverse_iterator rbegin() const noexcept;
441  constexpr reverse_iterator rend() const noexcept;
442 
443  //--------------------------------------------------------------------------
444  // Private Members
445  //--------------------------------------------------------------------------
446  private:
447 
448  using storage_type = detail::span_storage_type<element_type,Extent>;
449 
450  storage_type m_storage;
451  };
452 
453  //============================================================================
454  // non-member functions : class : span
455  //============================================================================
456 
457  //----------------------------------------------------------------------------
458  // Utilities
459  //----------------------------------------------------------------------------
460 
465  template <typename T, std::size_t N>
466  span<const byte, sizeof(T) * N> as_bytes(span<T, N> s) noexcept;
467 
472  template <typename T, std::size_t N>
473  span<byte, sizeof(T) * N> as_writable_bytes(span<T, N> s) noexcept;
474 
475 } // namespace bpstd
476 
477 template <typename T, std::size_t Extent>
478 constexpr std::size_t bpstd::span<T,Extent>::extent;
479 
480 //==============================================================================
481 // non-member functions : class : span
482 //==============================================================================
483 
484 //------------------------------------------------------------------------------
485 // Constructors
486 //------------------------------------------------------------------------------
487 
488 template <typename T, std::size_t Extent>
489 template <std::size_t UExtent, typename>
490 inline BPSTD_INLINE_VISIBILITY constexpr
492  noexcept
493  : m_storage{nullptr, detail::extent_storage<0>{}}
494 {
495 
496 }
497 
498 template <typename T, std::size_t Extent>
499 template <typename It,
500  bpstd::enable_if_t<(Extent == bpstd::dynamic_extent) &&
502 inline BPSTD_INLINE_VISIBILITY constexpr
503 bpstd::span<T,Extent>::span(It it, size_type count)
504  noexcept
505  : m_storage{to_address(it), count}
506 {
507 
508 }
509 
510 template <typename T, std::size_t Extent>
511 template <typename It,
512  bpstd::enable_if_t<(Extent != bpstd::dynamic_extent) &&
514 inline BPSTD_INLINE_VISIBILITY constexpr
515 bpstd::span<T,Extent>::span(It it, size_type count)
516  noexcept
517  : m_storage{to_address(it), count}
518 {
519 
520 }
521 
522 template <typename T, std::size_t Extent>
523 template <typename It, typename End,
524  bpstd::enable_if_t<(Extent == bpstd::dynamic_extent) &&
526 inline BPSTD_INLINE_VISIBILITY constexpr
527 bpstd::span<T,Extent>::span(It it, End end)
528  noexcept
529  : m_storage{to_address(it), static_cast<size_type>(end - it)}
530 {
531 
532 }
533 
534 template <typename T, std::size_t Extent>
535 template <typename It, typename End,
536  bpstd::enable_if_t<(Extent != bpstd::dynamic_extent) &&
538 inline BPSTD_INLINE_VISIBILITY constexpr
539 bpstd::span<T,Extent>::span(It it, End end)
540  noexcept
541  : m_storage{to_address(it), static_cast<size_type>(end - it)}
542 {
543 
544 }
545 
546 template <typename T, std::size_t Extent>
547 template <std::size_t N, typename>
548 inline BPSTD_INLINE_VISIBILITY constexpr
549 bpstd::span<T,Extent>::span(element_type (&arr)[N])
550  noexcept
551  : m_storage{static_cast<element_type*>(arr), detail::extent_storage<N>{}}
552 {
553 
554 }
555 
556 template <typename T, std::size_t Extent>
557 template <typename U, std::size_t N, typename>
558 inline BPSTD_INLINE_VISIBILITY constexpr
559 bpstd::span<T,Extent>::span(std::array<U, N>& arr)
560  noexcept
561  : m_storage{arr.data(), detail::extent_storage<N>{}}
562 {
563 
564 }
565 
566 template <typename T, std::size_t Extent>
567 template <typename U, std::size_t N, typename>
568 inline BPSTD_INLINE_VISIBILITY constexpr
569 bpstd::span<T,Extent>::span(const std::array<U, N>& arr)
570  noexcept
571  : m_storage{arr.data(), detail::extent_storage<N>{}}
572 {
573 
574 }
575 
576 template <typename T, std::size_t Extent>
577 template <typename U, std::size_t N, typename>
578 inline BPSTD_INLINE_VISIBILITY constexpr
579 bpstd::span<T,Extent>::span(const span<U, N>& s)
580  noexcept
581  : m_storage{s.data(), detail::extent_storage<N>{s.size()}}
582 {
583 
584 }
585 
586 //------------------------------------------------------------------------------
587 // Element Access
588 //------------------------------------------------------------------------------
589 
590 template <typename T, std::size_t Extent>
591 inline BPSTD_INLINE_VISIBILITY constexpr
592 typename bpstd::span<T,Extent>::reference
594  const noexcept
595 {
596  return data()[0];
597 }
598 
599 template <typename T, std::size_t Extent>
600 inline BPSTD_INLINE_VISIBILITY constexpr
601 typename bpstd::span<T,Extent>::reference
603  const noexcept
604 {
605  return data()[m_storage.size()-1];
606 }
607 
608 template <typename T, std::size_t Extent>
609 inline BPSTD_INLINE_VISIBILITY constexpr
610 typename bpstd::span<T,Extent>::reference
612  const noexcept
613 {
614  return data()[idx];
615 }
616 
617 template <typename T, std::size_t Extent>
618 inline BPSTD_INLINE_VISIBILITY constexpr
619 typename bpstd::span<T,Extent>::pointer
621  const noexcept
622 {
623  return m_storage.data();
624 }
625 
626 //------------------------------------------------------------------------------
627 // Observers
628 //------------------------------------------------------------------------------
629 
630 template <typename T, std::size_t Extent>
631 inline BPSTD_INLINE_VISIBILITY constexpr
632 typename bpstd::span<T,Extent>::size_type
634  const noexcept
635 {
636  return m_storage.size();
637 }
638 
639 template <typename T, std::size_t Extent>
640 inline BPSTD_INLINE_VISIBILITY constexpr
641 typename bpstd::span<T,Extent>::size_type
643  const noexcept
644 {
645  return size() * sizeof(T);
646 }
647 
648 template <typename T, std::size_t Extent>
649 inline BPSTD_INLINE_VISIBILITY constexpr
651  const noexcept
652 {
653  return size() == 0u;
654 }
655 
656 //------------------------------------------------------------------------------
657 // Subviews
658 //------------------------------------------------------------------------------
659 
660 template <typename T, std::size_t Extent>
661 template <std::size_t Count>
662 inline BPSTD_INLINE_VISIBILITY constexpr
665  const
666 {
667  static_assert(
668  Count <= Extent,
669  "A Count larger than Extent is ill-formed"
670  );
671 
672  return span<element_type, Count>{data(), Count};
673 }
674 
675 template <typename T, std::size_t Extent>
676 inline BPSTD_INLINE_VISIBILITY constexpr
679  const
680 {
681  return {data(), count};
682 }
683 
684 //------------------------------------------------------------------------------
685 
686 template <typename T, std::size_t Extent>
687 template <std::size_t Count>
688 inline BPSTD_INLINE_VISIBILITY constexpr
691  const
692 {
693  static_assert(
694  Count <= Extent,
695  "A Count larger than Extent is ill-formed"
696  );
697 
698  return span<element_type, Count>{data() + (size() - Count), Count};
699 }
700 
701 template <typename T, std::size_t Extent>
702 inline BPSTD_INLINE_VISIBILITY constexpr
705  const
706 {
707  return {data() + (size() - count), count};
708 }
709 
710 //------------------------------------------------------------------------------
711 
712 template <typename T, std::size_t Extent>
713 template <std::size_t Offset, std::size_t Count>
714 inline BPSTD_INLINE_VISIBILITY constexpr
715 bpstd::span<typename bpstd::span<T, Extent>::element_type, bpstd::detail::compute_subspan_size<Extent,Offset,Count>::value>
717  const
718 {
719  using result_type = span<
720  element_type,
721  detail::compute_subspan_size<Extent,Offset,Count>::value
722  >;
723 
724  return result_type{
725  data() + Offset,
726  (Count == dynamic_extent) ? (size() - Offset) : Count
727  };
728 }
729 
730 template <typename T, std::size_t Extent>
731 inline BPSTD_INLINE_VISIBILITY constexpr
733  bpstd::span<T, Extent>::subspan(std::size_t offset, std::size_t count)
734  const
735 {
736  return {
737  data() + offset,
738  (count == dynamic_extent) ? (size() - offset) : count
739  };
740 }
741 
742 //------------------------------------------------------------------------------
743 // Iterators
744 //------------------------------------------------------------------------------
745 
746 template <typename T, std::size_t Extent>
747 inline BPSTD_INLINE_VISIBILITY constexpr
748 typename bpstd::span<T,Extent>::iterator
750  const noexcept
751 {
752  return iterator{data()};
753 }
754 
755 template <typename T, std::size_t Extent>
756 inline BPSTD_INLINE_VISIBILITY constexpr
757 typename bpstd::span<T,Extent>::iterator
759  const noexcept
760 {
761  return iterator{data() + size()};
762 }
763 
764 template <typename T, std::size_t Extent>
765 inline BPSTD_INLINE_VISIBILITY constexpr
766 typename bpstd::span<T,Extent>::reverse_iterator
768  const noexcept
769 {
770  return reverse_iterator(end());
771 }
772 
773 template <typename T, std::size_t Extent>
774 inline BPSTD_INLINE_VISIBILITY constexpr
775 typename bpstd::span<T,Extent>::reverse_iterator
777  const noexcept
778 {
779  return reverse_iterator(begin());
780 }
781 
782 //==============================================================================
783 // non-member functions : class : span
784 //==============================================================================
785 
786 //------------------------------------------------------------------------------
787 // Utilities
788 //------------------------------------------------------------------------------
789 
790 template <typename T, std::size_t N>
791 inline bpstd::span<const bpstd::byte, sizeof(T) * N> bpstd::as_bytes(span<T, N> s)
792  noexcept
793 {
794  return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
795 }
796 
797 template <typename T, std::size_t N>
798 inline bpstd::span<bpstd::byte, sizeof(T) * N> bpstd::as_writable_bytes(span<T, N> s)
799  noexcept
800 {
801  return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
802 }
803 
804 BPSTD_COMPILER_DIAGNOSTIC_POSTAMBLE
805 
806 #endif /* BPSTD_SPAN_HPP */
bpstd::span::size
constexpr size_type size() const noexcept
Gets the number of elements in this span.
Definition: span.hpp:633
bpstd::span::empty
constexpr bool empty() const noexcept
Queries whether this span is empty.
Definition: span.hpp:650
bpstd::span::first
constexpr span< element_type, Count > first() const
Creates a subspan from the first Count elements.
type_traits.hpp
This header provides definitions from the C++ header <type_traits>
bpstd::size
constexpr auto size(const C &c) -> decltype(c.size())
Gets the size of a container.
bpstd::conjunction
Type trait to determine the bool_constant from a logical AND operation of other bool_constants.
Definition: type_traits.hpp:110
bpstd::to_address
constexpr T * to_address(T *p) noexcept
Converts a pointer-like type to a raw pointer by recursively calling to_address on it.
memory.hpp
This header provides definitions from the C++ header <memory>
bpstd::span
This class is a non-owning view of a contiguous piece of memory.
Definition: span.hpp:182
bpstd::span::last
constexpr span< element_type, Count > last() const
Creates a subspan from the last Count elements.
bpstd::span::operator[]
constexpr reference operator[](size_type idx) const noexcept
Gets a reference to the element at idx.
Definition: span.hpp:611
bpstd::as_bytes
span< const byte, sizeof(T) *N > as_bytes(span< T, N > s) noexcept
Converts a span s to a byte span.
bpstd::span::back
constexpr reference back() const noexcept
Gets a reference to the back element of this span.
Definition: span.hpp:602
bpstd::span::front
constexpr reference front() const noexcept
Gets a reference to the front element of this span.
Definition: span.hpp:593
bpstd::span::size_bytes
constexpr size_type size_bytes() const noexcept
Gets the number of bytes in this span.
Definition: span.hpp:642
bpstd::data
constexpr auto data(C &c) -> decltype(c.data())
Gets a pointer to the data from c.
bpstd::span::span
constexpr span() noexcept
Default-constructs a span.
bpstd::as_writable_bytes
span< byte, sizeof(T) *N > as_writable_bytes(span< T, N > s) noexcept
Converts a span s to a writable byte span.
bpstd::span::operator=
BPSTD_CPP14_CONSTEXPR span & operator=(const span &other) noexcept=default
Assigns a span from other.
cstddef.hpp
This header provides definitions from the C++ header <cstddef>
bpstd::span::subspan
constexpr span< element_type, detail::compute_subspan_size< Extent, Offset, Count >::value > subspan() const
Creates a subspan that is Count elements long, Offset from the start of this span.
bpstd::span::data
constexpr pointer data() const noexcept
Gets a pointer to the start of the data.
Definition: span.hpp:620