// Components for manipulating non-owning sequences of objects -*- C++ -*- // Copyright (C) 2019-2020 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 3, or (at your option) // any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // Under Section 7 of GPL version 3, you are granted additional // permissions described in the GCC Runtime Library Exception, version // 3.1, as published by the Free Software Foundation. // You should have received a copy of the GNU General Public License and // a copy of the GCC Runtime Library Exception along with this program; // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see // . /** @file span * This is a Standard C++ Library header. */ // // P0122 span library // Contributed by ThePhD // #ifndef _GLIBCXX_SPAN #define _GLIBCXX_SPAN 1 #pragma GCC system_header #if __cplusplus > 201703L #include #include #include #include #if __cpp_lib_concepts namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION #define __cpp_lib_span 201902L inline constexpr size_t dynamic_extent = static_cast(-1); template class span; namespace __detail { template struct __is_std_span : false_type { }; template struct __is_std_span> : true_type { }; template struct __is_std_array : false_type { }; template struct __is_std_array<_GLIBCXX_STD_C::array<_Tp, _Num>> : true_type { }; #ifdef _GLIBCXX_DEBUG template struct __is_std_array<__debug::array<_Tp, _Num>> : true_type { }; #endif template class __extent_storage { public: constexpr __extent_storage(size_t) noexcept { } static constexpr size_t _M_extent() noexcept { return _Extent; } }; template<> class __extent_storage { public: constexpr __extent_storage(size_t __extent) noexcept : _M_extent_value(__extent) { } constexpr size_t _M_extent() const noexcept { return this->_M_extent_value; } private: size_t _M_extent_value; }; } // namespace __detail template class span { template static constexpr size_t _S_subspan_extent() { if constexpr (_Count != dynamic_extent) return _Count; else if constexpr (extent != dynamic_extent) return _Extent - _Offset; else return dynamic_extent; } // _GLIBCXX_RESOLVE_LIB_DEFECTS // 3255. span's array constructor is too strict template using __is_compatible_array = __and_< bool_constant<(_Extent == dynamic_extent || _ArrayExtent == _Extent)>, __is_array_convertible<_Type, _Tp>>; template> using __is_compatible_iterator = __and_< bool_constant>, is_lvalue_reference>, is_same, remove_cvref_t<_Ref>>, __is_array_convertible<_Type, remove_reference_t<_Ref>>>; template using __is_compatible_range = __is_compatible_iterator>; public: // member types using value_type = remove_cv_t<_Type>; using element_type = _Type; using size_type = size_t; using reference = element_type&; using const_reference = const element_type&; using pointer = _Type*; using const_pointer = const _Type*; using iterator = __gnu_cxx::__normal_iterator; using const_iterator = __gnu_cxx::__normal_iterator; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; using difference_type = ptrdiff_t; // member constants static inline constexpr size_t extent = _Extent; // constructors constexpr span() noexcept requires ((_Extent + 1u) <= 1u) : _M_extent(0), _M_ptr(nullptr) { } constexpr span(const span&) noexcept = default; template requires (__is_compatible_array<_Tp, _ArrayExtent>::value) constexpr span(_Tp (&__arr)[_ArrayExtent]) noexcept : span(static_cast(__arr), _ArrayExtent) { } template requires (__is_compatible_array<_Tp, _ArrayExtent>::value) constexpr span(array<_Tp, _ArrayExtent>& __arr) noexcept : span(static_cast(__arr.data()), _ArrayExtent) { } template requires (__is_compatible_array::value) constexpr span(const array<_Tp, _ArrayExtent>& __arr) noexcept : span(static_cast(__arr.data()), _ArrayExtent) { } public: template requires (_Extent == dynamic_extent) && (!__detail::__is_std_span>::value) && (!__detail::__is_std_array>::value) && (!is_array_v>) && (__is_compatible_range<_Range>::value) constexpr span(_Range&& __range) noexcept(noexcept(ranges::data(__range)) && noexcept(ranges::size(__range))) : span(ranges::data(__range), ranges::size(__range)) { } template _Sentinel> requires (__is_compatible_iterator<_ContiguousIterator>::value) && (!is_convertible_v<_Sentinel, size_type>) constexpr span(_ContiguousIterator __first, _Sentinel __last) noexcept(noexcept(__last - __first)) : _M_extent(static_cast(__last - __first)), _M_ptr(std::to_address(__first)) { if (_Extent != dynamic_extent) __glibcxx_assert((__last - __first) == _Extent); } template requires (__is_compatible_iterator<_ContiguousIterator>::value) constexpr span(_ContiguousIterator __first, size_type __count) noexcept : _M_extent(__count), _M_ptr(std::to_address(__first)) { __glibcxx_assert(_Extent == dynamic_extent || __count == _Extent); } template requires (_Extent == dynamic_extent || _Extent == _OExtent) && (__is_array_convertible<_Type, _OType>::value) constexpr span(const span<_OType, _OExtent>& __s) noexcept : _M_extent(__s.size()), _M_ptr(__s.data()) { } // assignment constexpr span& operator=(const span&) noexcept = default; // observers constexpr size_type size() const noexcept { return this->_M_extent._M_extent(); } constexpr size_type size_bytes() const noexcept { return this->_M_extent._M_extent() * sizeof(element_type); } [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; } // element access constexpr reference front() const noexcept { static_assert(extent != 0); __glibcxx_assert(!empty()); return *this->_M_ptr; } constexpr reference back() const noexcept { static_assert(extent != 0); __glibcxx_assert(!empty()); return *(this->_M_ptr + (size() - 1)); } constexpr reference operator[](size_type __idx) const noexcept { static_assert(extent != 0); __glibcxx_assert(__idx < size()); return *(this->_M_ptr + __idx); } constexpr pointer data() const noexcept { return this->_M_ptr; } // iterator support constexpr iterator begin() const noexcept { return iterator(this->_M_ptr); } constexpr const_iterator cbegin() const noexcept { return const_iterator(this->_M_ptr); } constexpr iterator end() const noexcept { return iterator(this->_M_ptr + this->size()); } constexpr const_iterator cend() const noexcept { return const_iterator(this->_M_ptr + this->size()); } constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator(this->end()); } constexpr const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(this->cend()); } constexpr reverse_iterator rend() const noexcept { return reverse_iterator(this->begin()); } constexpr const_reverse_iterator crend() const noexcept { return const_reverse_iterator(this->cbegin()); } // subviews template constexpr span first() const noexcept { if constexpr (_Extent == dynamic_extent) __glibcxx_assert(_Count <= size()); else static_assert(_Count <= extent); return { this->data(), _Count }; } constexpr span first(size_type __count) const noexcept { __glibcxx_assert(__count <= size()); return { this->data(), __count }; } template constexpr span last() const noexcept { if constexpr (_Extent == dynamic_extent) __glibcxx_assert(_Count <= size()); else static_assert(_Count <= extent); return { this->data() + (this->size() - _Count), _Count }; } constexpr span last(size_type __count) const noexcept { __glibcxx_assert(__count <= size()); return { this->data() + (this->size() - __count), __count }; } template constexpr auto subspan() const noexcept -> span()> { if constexpr (_Extent == dynamic_extent) __glibcxx_assert(_Offset <= size()); else static_assert(_Offset <= extent); if constexpr (_Count == dynamic_extent) return { this->data() + _Offset, this->size() - _Offset }; else { if constexpr (_Extent == dynamic_extent) { __glibcxx_assert(_Count <= size()); __glibcxx_assert(_Count <= (size() - _Offset)); } else { static_assert(_Count <= extent); static_assert(_Count <= (extent - _Offset)); } return { this->data() + _Offset, _Count }; } } constexpr span subspan(size_type __offset, size_type __count = dynamic_extent) const noexcept { __glibcxx_assert(__offset <= size()); if (__count == dynamic_extent) __count = this->size() - __offset; else { __glibcxx_assert(__count <= size()); __glibcxx_assert(__offset + __count <= size()); } return {this->data() + __offset, __count}; } private: [[no_unique_address]] __detail::__extent_storage _M_extent; pointer _M_ptr; }; // deduction guides template span(_Type(&)[_ArrayExtent]) -> span<_Type, _ArrayExtent>; template span(array<_Type, _ArrayExtent>&) -> span<_Type, _ArrayExtent>; template span(const array<_Type, _ArrayExtent>&) -> span; template span(_Iter, _Sentinel) -> span>>; template span(_Range &&) -> span>>; template inline span as_bytes(span<_Type, _Extent> __sp) noexcept { return {reinterpret_cast(__sp.data()), __sp.size_bytes()}; } template inline span as_writable_bytes(span<_Type, _Extent> __sp) noexcept { return {reinterpret_cast(__sp.data()), __sp.size_bytes()}; } // tuple helpers template constexpr _Type& get(span<_Type, _Extent> __sp) noexcept { static_assert(_Extent != dynamic_extent && _Index < _Extent, "get can only be used with a span of non-dynamic (fixed) extent"); return __sp[_Index]; } template struct tuple_size; template struct tuple_element; template struct tuple_size> : public integral_constant { static_assert(_Extent != dynamic_extent, "tuple_size can only " "be used with a span of non-dynamic (fixed) extent"); }; template struct tuple_element<_Index, span<_Type, _Extent>> { static_assert(_Extent != dynamic_extent, "tuple_element can only " "be used with a span of non-dynamic (fixed) extent"); static_assert(_Index < _Extent, "Index is less than Extent"); using type = _Type; }; namespace ranges { template extern inline const bool enable_safe_range; // Opt-in to safe_range concept template inline constexpr bool enable_safe_range> = true; } _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // concepts #endif // C++20 #endif // _GLIBCXX_SPAN