Home | History | Annotate | Line # | Download | only in std
      1 // Components for manipulating non-owning sequences of objects -*- C++ -*-
      2 
      3 // Copyright (C) 2019-2022 Free Software Foundation, Inc.
      4 //
      5 // This file is part of the GNU ISO C++ Library.  This library is free
      6 // software; you can redistribute it and/or modify it under the
      7 // terms of the GNU General Public License as published by the
      8 // Free Software Foundation; either version 3, or (at your option)
      9 // any later version.
     10 
     11 // This library is distributed in the hope that it will be useful,
     12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 // GNU General Public License for more details.
     15 
     16 // Under Section 7 of GPL version 3, you are granted additional
     17 // permissions described in the GCC Runtime Library Exception, version
     18 // 3.1, as published by the Free Software Foundation.
     19 
     20 // You should have received a copy of the GNU General Public License and
     21 // a copy of the GCC Runtime Library Exception along with this program;
     22 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     23 // <http://www.gnu.org/licenses/>.
     24 
     25 /** @file span
     26  *  This is a Standard C++ Library header.
     27  */
     28 
     29 //
     30 // P0122 span library
     31 // Contributed by ThePhD
     32 //
     33 
     34 #ifndef _GLIBCXX_SPAN
     35 #define _GLIBCXX_SPAN 1
     36 
     37 #pragma GCC system_header
     38 
     39 #if __cplusplus > 201703L
     40 
     41 #include <array>
     42 #include <cstddef>
     43 #include <bits/stl_iterator.h>
     44 #include <bits/ranges_base.h>
     45 
     46 #if __cpp_lib_concepts
     47 namespace std _GLIBCXX_VISIBILITY(default)
     48 {
     49 _GLIBCXX_BEGIN_NAMESPACE_VERSION
     50 
     51 #define __cpp_lib_span 202002L
     52 
     53   inline constexpr size_t dynamic_extent = static_cast<size_t>(-1);
     54 
     55   template<typename _Type, size_t _Extent>
     56     class span;
     57 
     58   namespace __detail
     59   {
     60     template<typename _Tp>
     61       inline constexpr bool __is_span = false;
     62 
     63     template<typename _Tp, size_t _Num>
     64       inline constexpr bool __is_span<span<_Tp, _Num>> = true;
     65 
     66     template<typename _Tp>
     67       inline constexpr bool __is_std_array = false;
     68 
     69     template<typename _Tp, size_t _Num>
     70       inline constexpr bool __is_std_array<std::array<_Tp, _Num>> = true;
     71 
     72     template<size_t _Extent>
     73       class __extent_storage
     74       {
     75       public:
     76 	constexpr
     77 	__extent_storage(size_t) noexcept
     78 	{ }
     79 
     80 	static constexpr size_t
     81 	_M_extent() noexcept
     82 	{ return _Extent; }
     83       };
     84 
     85     template<>
     86       class __extent_storage<dynamic_extent>
     87       {
     88       public:
     89 	constexpr
     90 	__extent_storage(size_t __extent) noexcept
     91 	: _M_extent_value(__extent)
     92 	{ }
     93 
     94 	constexpr size_t
     95 	_M_extent() const noexcept
     96 	{ return this->_M_extent_value; }
     97 
     98       private:
     99 	size_t _M_extent_value;
    100       };
    101   } // namespace __detail
    102 
    103   template<typename _Type, size_t _Extent = dynamic_extent>
    104     class span
    105     {
    106       template<size_t _Offset, size_t _Count>
    107 	static constexpr size_t
    108 	_S_subspan_extent()
    109 	{
    110 	  if constexpr (_Count != dynamic_extent)
    111 	    return _Count;
    112 	  else if constexpr (extent != dynamic_extent)
    113 	    return _Extent - _Offset;
    114 	  else
    115 	    return dynamic_extent;
    116 	}
    117 
    118       // _GLIBCXX_RESOLVE_LIB_DEFECTS
    119       // 3255. span's array constructor is too strict
    120       template<typename _Tp, size_t _ArrayExtent>
    121 	requires (_Extent == dynamic_extent || _ArrayExtent == _Extent)
    122 	using __is_compatible_array = __is_array_convertible<_Type, _Tp>;
    123 
    124       template<typename _Ref>
    125 	using __is_compatible_ref
    126 	  = __is_array_convertible<_Type, remove_reference_t<_Ref>>;
    127 
    128     public:
    129       // member types
    130       using element_type           = _Type;
    131       using value_type             = remove_cv_t<_Type>;
    132       using size_type              = size_t;
    133       using difference_type        = ptrdiff_t;
    134       using pointer                = _Type*;
    135       using const_pointer          = const _Type*;
    136       using reference              = element_type&;
    137       using const_reference        = const element_type&;
    138       using iterator = __gnu_cxx::__normal_iterator<pointer, span>;
    139       using reverse_iterator       = std::reverse_iterator<iterator>;
    140 
    141       // member constants
    142       static constexpr size_t extent = _Extent;
    143 
    144       // constructors, copy and assignment
    145 
    146       constexpr
    147       span() noexcept
    148       requires ((_Extent + 1u) <= 1u)
    149       : _M_ptr(nullptr), _M_extent(0)
    150       { }
    151 
    152       template<contiguous_iterator _It>
    153 	requires __is_compatible_ref<iter_reference_t<_It>>::value
    154 	constexpr explicit(extent != dynamic_extent)
    155 	span(_It __first, size_type __count)
    156 	noexcept
    157 	: _M_ptr(std::to_address(__first)), _M_extent(__count)
    158 	{
    159 	  if constexpr (_Extent != dynamic_extent)
    160 	    {
    161 	      __glibcxx_assert(__count == _Extent);
    162 	    }
    163 	  __glibcxx_requires_valid_range(__first, __first + __count);
    164 	}
    165 
    166       template<contiguous_iterator _It, sized_sentinel_for<_It> _End>
    167 	requires __is_compatible_ref<iter_reference_t<_It>>::value
    168 	  && (!is_convertible_v<_End, size_type>)
    169 	constexpr explicit(extent != dynamic_extent)
    170 	span(_It __first, _End __last)
    171 	noexcept(noexcept(__last - __first))
    172 	: _M_ptr(std::to_address(__first)),
    173 	  _M_extent(static_cast<size_type>(__last - __first))
    174 	{
    175 	  if constexpr (_Extent != dynamic_extent)
    176 	    {
    177 	      __glibcxx_assert((__last - __first) == _Extent);
    178 	    }
    179 	  __glibcxx_requires_valid_range(__first, __last);
    180 	}
    181 
    182       template<size_t _ArrayExtent>
    183 	requires (_Extent == dynamic_extent || _ArrayExtent == _Extent)
    184 	constexpr
    185 	span(type_identity_t<element_type> (&__arr)[_ArrayExtent]) noexcept
    186 	: _M_ptr(__arr), _M_extent(_ArrayExtent)
    187 	{ }
    188 
    189       template<typename _Tp, size_t _ArrayExtent>
    190 	requires __is_compatible_array<_Tp, _ArrayExtent>::value
    191 	constexpr
    192 	span(array<_Tp, _ArrayExtent>& __arr) noexcept
    193 	: _M_ptr(__arr.data()), _M_extent(_ArrayExtent)
    194 	{ }
    195 
    196       template<typename _Tp, size_t _ArrayExtent>
    197 	requires __is_compatible_array<const _Tp, _ArrayExtent>::value
    198 	constexpr
    199 	span(const array<_Tp, _ArrayExtent>& __arr) noexcept
    200 	: _M_ptr(__arr.data()), _M_extent(_ArrayExtent)
    201 	{ }
    202 
    203       template<typename _Range>
    204 	requires (!__detail::__is_span<remove_cvref_t<_Range>>)
    205 	  && (!__detail::__is_std_array<remove_cvref_t<_Range>>)
    206 	  && (!is_array_v<remove_cvref_t<_Range>>)
    207 	  && ranges::contiguous_range<_Range> && ranges::sized_range<_Range>
    208 	  && (ranges::borrowed_range<_Range> || is_const_v<element_type>)
    209 	  && __is_compatible_ref<ranges::range_reference_t<_Range>>::value
    210 	constexpr explicit(extent != dynamic_extent)
    211 	span(_Range&& __range)
    212 	noexcept(noexcept(ranges::data(__range))
    213 		  && noexcept(ranges::size(__range)))
    214 	: _M_ptr(ranges::data(__range)), _M_extent(ranges::size(__range))
    215 	{
    216 	  if constexpr (extent != dynamic_extent)
    217 	    {
    218 	      __glibcxx_assert(ranges::size(__range) == extent);
    219 	    }
    220 	}
    221 
    222       constexpr
    223       span(const span&) noexcept = default;
    224 
    225       template<typename _OType, size_t _OExtent>
    226 	requires (_Extent == dynamic_extent || _OExtent == dynamic_extent
    227 		  || _Extent == _OExtent)
    228 	  && (__is_array_convertible<_Type, _OType>::value)
    229 	constexpr
    230 	explicit(extent != dynamic_extent && _OExtent == dynamic_extent)
    231 	span(const span<_OType, _OExtent>& __s) noexcept
    232 	: _M_ptr(__s.data()), _M_extent(__s.size())
    233 	{
    234 	  if constexpr (extent != dynamic_extent)
    235 	    {
    236 	      __glibcxx_assert(__s.size() == extent);
    237 	    }
    238 	}
    239 
    240       ~span() noexcept = default;
    241 
    242       constexpr span&
    243       operator=(const span&) noexcept = default;
    244 
    245       // observers
    246 
    247       constexpr size_type
    248       size() const noexcept
    249       { return this->_M_extent._M_extent(); }
    250 
    251       constexpr size_type
    252       size_bytes() const noexcept
    253       { return this->_M_extent._M_extent() * sizeof(element_type); }
    254 
    255       [[nodiscard]] constexpr bool
    256       empty() const noexcept
    257       { return size() == 0; }
    258 
    259       // element access
    260 
    261       constexpr reference
    262       front() const noexcept
    263       {
    264 	__glibcxx_assert(!empty());
    265 	return *this->_M_ptr;
    266       }
    267 
    268       constexpr reference
    269       back() const noexcept
    270       {
    271 	__glibcxx_assert(!empty());
    272 	return *(this->_M_ptr + (size() - 1));
    273       }
    274 
    275       constexpr reference
    276       operator[](size_type __idx) const noexcept
    277       {
    278 	__glibcxx_assert(__idx < size());
    279 	return *(this->_M_ptr + __idx);
    280       }
    281 
    282       constexpr pointer
    283       data() const noexcept
    284       { return this->_M_ptr; }
    285 
    286       // iterator support
    287 
    288       constexpr iterator
    289       begin() const noexcept
    290       { return iterator(this->_M_ptr); }
    291 
    292       constexpr iterator
    293       end() const noexcept
    294       { return iterator(this->_M_ptr + this->size()); }
    295 
    296       constexpr reverse_iterator
    297       rbegin() const noexcept
    298       { return reverse_iterator(this->end()); }
    299 
    300       constexpr reverse_iterator
    301       rend() const noexcept
    302       { return reverse_iterator(this->begin()); }
    303 
    304       // subviews
    305 
    306       template<size_t _Count>
    307 	constexpr span<element_type, _Count>
    308 	first() const noexcept
    309 	{
    310 	  if constexpr (_Extent == dynamic_extent)
    311 	    __glibcxx_assert(_Count <= size());
    312 	  else
    313 	    static_assert(_Count <= extent);
    314 	  using _Sp = span<element_type, _Count>;
    315 	  return _Sp{ this->data(), _Count };
    316 	}
    317 
    318       constexpr span<element_type, dynamic_extent>
    319       first(size_type __count) const noexcept
    320       {
    321 	__glibcxx_assert(__count <= size());
    322 	return { this->data(), __count };
    323       }
    324 
    325       template<size_t _Count>
    326 	constexpr span<element_type, _Count>
    327 	last() const noexcept
    328 	{
    329 	  if constexpr (_Extent == dynamic_extent)
    330 	    __glibcxx_assert(_Count <= size());
    331 	  else
    332 	    static_assert(_Count <= extent);
    333 	  using _Sp = span<element_type, _Count>;
    334 	  return _Sp{ this->data() + (this->size() - _Count), _Count };
    335 	}
    336 
    337       constexpr span<element_type, dynamic_extent>
    338       last(size_type __count) const noexcept
    339       {
    340 	__glibcxx_assert(__count <= size());
    341 	return { this->data() + (this->size() - __count), __count };
    342       }
    343 
    344       template<size_t _Offset, size_t _Count = dynamic_extent>
    345 	constexpr auto
    346 	subspan() const noexcept
    347 	-> span<element_type, _S_subspan_extent<_Offset, _Count>()>
    348 	{
    349 	  if constexpr (_Extent == dynamic_extent)
    350 	    {
    351 	      __glibcxx_assert(_Offset <= size());
    352 	    }
    353 	  else
    354 	    static_assert(_Offset <= extent);
    355 
    356 	  using _Sp = span<element_type, _S_subspan_extent<_Offset, _Count>()>;
    357 
    358 	  if constexpr (_Count == dynamic_extent)
    359 	    return _Sp{ this->data() + _Offset, this->size() - _Offset };
    360 	  else
    361 	    {
    362 	      if constexpr (_Extent == dynamic_extent)
    363 		{
    364 		  __glibcxx_assert(_Count <= size());
    365 		  __glibcxx_assert(_Count <= (size() - _Offset));
    366 		}
    367 	      else
    368 		{
    369 		  static_assert(_Count <= extent);
    370 		  static_assert(_Count <= (extent - _Offset));
    371 		}
    372 	      return _Sp{ this->data() + _Offset, _Count };
    373 	    }
    374 	}
    375 
    376       constexpr span<element_type, dynamic_extent>
    377       subspan(size_type __offset, size_type __count = dynamic_extent) const
    378       noexcept
    379       {
    380 	__glibcxx_assert(__offset <= size());
    381 	if (__count == dynamic_extent)
    382 	  __count = this->size() - __offset;
    383 	else
    384 	  {
    385 	    __glibcxx_assert(__count <= size());
    386 	    __glibcxx_assert(__offset + __count <= size());
    387 	  }
    388 	return {this->data() + __offset, __count};
    389       }
    390 
    391     private:
    392       pointer _M_ptr;
    393       [[no_unique_address]] __detail::__extent_storage<extent> _M_extent;
    394     };
    395 
    396   // deduction guides
    397 
    398   template<typename _Type, size_t _ArrayExtent>
    399     span(_Type(&)[_ArrayExtent]) -> span<_Type, _ArrayExtent>;
    400 
    401   template<typename _Type, size_t _ArrayExtent>
    402     span(array<_Type, _ArrayExtent>&) -> span<_Type, _ArrayExtent>;
    403 
    404   template<typename _Type, size_t _ArrayExtent>
    405     span(const array<_Type, _ArrayExtent>&)
    406       -> span<const _Type, _ArrayExtent>;
    407 
    408   template<contiguous_iterator _Iter, typename _End>
    409     span(_Iter, _End)
    410       -> span<remove_reference_t<iter_reference_t<_Iter>>>;
    411 
    412   template<ranges::contiguous_range _Range>
    413     span(_Range &&)
    414       -> span<remove_reference_t<ranges::range_reference_t<_Range&>>>;
    415 
    416   template<typename _Type, size_t _Extent>
    417     inline
    418     span<const byte, _Extent == dynamic_extent
    419 	? dynamic_extent : _Extent * sizeof(_Type)>
    420     as_bytes(span<_Type, _Extent> __sp) noexcept
    421     {
    422       auto data = reinterpret_cast<const byte*>(__sp.data());
    423       auto size = __sp.size_bytes();
    424       constexpr auto extent = _Extent == dynamic_extent
    425 	? dynamic_extent : _Extent * sizeof(_Type);
    426       return span<const byte, extent>{data, size};
    427     }
    428 
    429   template<typename _Type, size_t _Extent>
    430     requires (!is_const_v<_Type>)
    431     inline
    432     span<byte, _Extent == dynamic_extent
    433        ? dynamic_extent : _Extent * sizeof(_Type)>
    434     as_writable_bytes(span<_Type, _Extent> __sp) noexcept
    435     {
    436       auto data = reinterpret_cast<byte*>(__sp.data());
    437       auto size = __sp.size_bytes();
    438       constexpr auto extent = _Extent == dynamic_extent
    439 	? dynamic_extent : _Extent * sizeof(_Type);
    440       return span<byte, extent>{data, size};
    441     }
    442 
    443   namespace ranges
    444   {
    445     // Opt-in to borrowed_range concept
    446     template<typename _ElementType, size_t _Extent>
    447       inline constexpr bool
    448 	enable_borrowed_range<span<_ElementType, _Extent>> = true;
    449 
    450     // Opt-in to view concept
    451     template<typename _ElementType, size_t _Extent>
    452       inline constexpr bool
    453 	enable_view<span<_ElementType, _Extent>> = true;
    454   }
    455 _GLIBCXX_END_NAMESPACE_VERSION
    456 } // namespace std
    457 #endif // concepts
    458 #endif // C++20
    459 #endif // _GLIBCXX_SPAN
    460