The debug mode has been broken pretty much ever since it was shipped because it was possible to enable the debug mode in user code without actually enabling it in the dylib, leading to ODR violations that caused various kinds of failures. This commit makes the debug mode a knob that is configured when building the library and which can't be changed afterwards. This is less flexible for users, however it will actually work as intended and it will allow us, in the future, to add various kinds of checks that do not assume the same ABI as the normal library. Furthermore, this will make the debug mode more robust, which means that vendors might be more tempted to support it properly, which hasn't been the case with the current debug mode. This patch shouldn't break any user code, except folks who are building against a library that doesn't have the debug mode enabled and who try to enable the debug mode in their code. Such users will get a compile-time error explaining that this configuration isn't supported anymore. In the future, we should further increase the granularity of the debug mode checks so that we can cherry-pick which checks to enable, like we do for unspecified behavior randomization. Differential Revision: https://reviews.llvm.org/D122941
658 lines
26 KiB
C++
658 lines
26 KiB
C++
// -*- C++ -*-
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===---------------------------------------------------------------------===//
|
|
|
|
#ifndef _LIBCPP_SPAN
|
|
#define _LIBCPP_SPAN
|
|
|
|
/*
|
|
span synopsis
|
|
|
|
namespace std {
|
|
|
|
// constants
|
|
inline constexpr size_t dynamic_extent = numeric_limits<size_t>::max();
|
|
|
|
// [views.span], class template span
|
|
template <class ElementType, size_t Extent = dynamic_extent>
|
|
class span;
|
|
|
|
template<class ElementType, size_t Extent>
|
|
inline constexpr bool ranges::enable_view<span<ElementType, Extent>> = true;
|
|
|
|
template<class ElementType, size_t Extent>
|
|
inline constexpr bool ranges::enable_borrowed_range<span<ElementType, Extent>> = true;
|
|
|
|
// [span.objectrep], views of object representation
|
|
template <class ElementType, size_t Extent>
|
|
span<const byte, ((Extent == dynamic_extent) ? dynamic_extent :
|
|
(sizeof(ElementType) * Extent))> as_bytes(span<ElementType, Extent> s) noexcept;
|
|
|
|
template <class ElementType, size_t Extent>
|
|
span< byte, ((Extent == dynamic_extent) ? dynamic_extent :
|
|
(sizeof(ElementType) * Extent))> as_writable_bytes(span<ElementType, Extent> s) noexcept;
|
|
|
|
|
|
template <class ElementType, size_t Extent = dynamic_extent>
|
|
class span {
|
|
public:
|
|
// constants and types
|
|
using element_type = ElementType;
|
|
using value_type = remove_cv_t<ElementType>;
|
|
using size_type = size_t;
|
|
using difference_type = ptrdiff_t;
|
|
using pointer = element_type*;
|
|
using const_pointer = const element_type*;
|
|
using reference = element_type&;
|
|
using const_reference = const element_type&;
|
|
using iterator = implementation-defined;
|
|
using reverse_iterator = std::reverse_iterator<iterator>;
|
|
static constexpr size_type extent = Extent;
|
|
|
|
// [span.cons], span constructors, copy, assignment, and destructor
|
|
constexpr span() noexcept;
|
|
template <class It>
|
|
constexpr explicit(Extent != dynamic_extent) span(It first, size_type count);
|
|
template <class It, class End>
|
|
constexpr explicit(Extent != dynamic_extent) span(It first, End last);
|
|
template <size_t N>
|
|
constexpr span(type_identity_t<element_type> (&arr)[N]) noexcept;
|
|
template <size_t N>
|
|
constexpr span(array<value_type, N>& arr) noexcept;
|
|
template <size_t N>
|
|
constexpr span(const array<value_type, N>& arr) noexcept;
|
|
template<class R>
|
|
constexpr explicit(Extent != dynamic_extent) span(R&& r);
|
|
constexpr span(const span& other) noexcept = default;
|
|
template <class OtherElementType, size_t OtherExtent>
|
|
constexpr explicit(Extent != dynamic_extent) span(const span<OtherElementType, OtherExtent>& s) noexcept;
|
|
~span() noexcept = default;
|
|
constexpr span& operator=(const span& other) noexcept = default;
|
|
|
|
// [span.sub], span subviews
|
|
template <size_t Count>
|
|
constexpr span<element_type, Count> first() const;
|
|
template <size_t Count>
|
|
constexpr span<element_type, Count> last() const;
|
|
template <size_t Offset, size_t Count = dynamic_extent>
|
|
constexpr span<element_type, see below> subspan() const;
|
|
|
|
constexpr span<element_type, dynamic_extent> first(size_type count) const;
|
|
constexpr span<element_type, dynamic_extent> last(size_type count) const;
|
|
constexpr span<element_type, dynamic_extent> subspan(size_type offset, size_type count = dynamic_extent) const;
|
|
|
|
// [span.obs], span observers
|
|
constexpr size_type size() const noexcept;
|
|
constexpr size_type size_bytes() const noexcept;
|
|
[[nodiscard]] constexpr bool empty() const noexcept;
|
|
|
|
// [span.elem], span element access
|
|
constexpr reference operator[](size_type idx) const;
|
|
constexpr reference front() const;
|
|
constexpr reference back() const;
|
|
constexpr pointer data() const noexcept;
|
|
|
|
// [span.iterators], span iterator support
|
|
constexpr iterator begin() const noexcept;
|
|
constexpr iterator end() const noexcept;
|
|
constexpr reverse_iterator rbegin() const noexcept;
|
|
constexpr reverse_iterator rend() const noexcept;
|
|
|
|
private:
|
|
pointer data_; // exposition only
|
|
size_type size_; // exposition only
|
|
};
|
|
|
|
template<class It, class EndOrSize>
|
|
span(It, EndOrSize) -> span<remove_reference_t<iter_reference_t<_It>>>;
|
|
|
|
template<class T, size_t N>
|
|
span(T (&)[N]) -> span<T, N>;
|
|
|
|
template<class T, size_t N>
|
|
span(array<T, N>&) -> span<T, N>;
|
|
|
|
template<class T, size_t N>
|
|
span(const array<T, N>&) -> span<const T, N>;
|
|
|
|
template<class R>
|
|
span(R&&) -> span<remove_reference_t<ranges::range_reference_t<R>>>;
|
|
|
|
} // namespace std
|
|
|
|
*/
|
|
|
|
#include <__assert> // all public C++ headers provide the assertion handler
|
|
#include <__config>
|
|
#include <__debug>
|
|
#include <__fwd/span.h>
|
|
#include <__iterator/concepts.h>
|
|
#include <__iterator/wrap_iter.h>
|
|
#include <__ranges/concepts.h>
|
|
#include <__ranges/data.h>
|
|
#include <__ranges/enable_borrowed_range.h>
|
|
#include <__ranges/enable_view.h>
|
|
#include <__ranges/size.h>
|
|
#include <__utility/forward.h>
|
|
#include <array> // for array
|
|
#include <cstddef> // for byte
|
|
#include <iterator> // for iterators
|
|
#include <limits>
|
|
#include <type_traits> // for remove_cv, etc
|
|
#include <version>
|
|
|
|
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
|
# pragma GCC system_header
|
|
#endif
|
|
|
|
_LIBCPP_PUSH_MACROS
|
|
#include <__undef_macros>
|
|
|
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
|
|
|
#if _LIBCPP_STD_VER > 17
|
|
|
|
template <class _Tp>
|
|
struct __is_std_array : false_type {};
|
|
|
|
template <class _Tp, size_t _Sz>
|
|
struct __is_std_array<array<_Tp, _Sz>> : true_type {};
|
|
|
|
template <class _Tp>
|
|
struct __is_std_span : false_type {};
|
|
|
|
template <class _Tp, size_t _Sz>
|
|
struct __is_std_span<span<_Tp, _Sz>> : true_type {};
|
|
|
|
#if defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
|
|
// This is a temporary workaround until we ship <ranges> -- we've unfortunately been
|
|
// shipping <span> before its API was finalized, and we used to provide a constructor
|
|
// from container types that had the requirements below. To avoid breaking code that
|
|
// has started relying on the range-based constructor until we ship all of <ranges>,
|
|
// we emulate the constructor requirements like this.
|
|
template <class _Range, class _ElementType>
|
|
concept __span_compatible_range =
|
|
!__is_std_span<remove_cvref_t<_Range>>::value &&
|
|
!__is_std_array<remove_cvref_t<_Range>>::value &&
|
|
!is_array_v<remove_cvref_t<_Range>> &&
|
|
requires (_Range&& __r) {
|
|
data(std::forward<_Range>(__r));
|
|
size(std::forward<_Range>(__r));
|
|
} &&
|
|
is_convertible_v<remove_reference_t<ranges::range_reference_t<_Range>>(*)[], _ElementType(*)[]>;
|
|
#else
|
|
template <class _Range, class _ElementType>
|
|
concept __span_compatible_range =
|
|
ranges::contiguous_range<_Range> &&
|
|
ranges::sized_range<_Range> &&
|
|
(ranges::borrowed_range<_Range> || is_const_v<_ElementType>) &&
|
|
!__is_std_span<remove_cvref_t<_Range>>::value &&
|
|
!__is_std_array<remove_cvref_t<_Range>>::value &&
|
|
!is_array_v<remove_cvref_t<_Range>> &&
|
|
is_convertible_v<remove_reference_t<ranges::range_reference_t<_Range>>(*)[], _ElementType(*)[]>;
|
|
#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
|
|
|
|
#if defined(_LIBCPP_ENABLE_DEBUG_MODE) || defined(_LIBCPP_ABI_SPAN_POINTER_ITERATORS)
|
|
# define _LIBCPP_SPAN_USE_POINTER_ITERATOR
|
|
#endif
|
|
|
|
template <typename _Tp, size_t _Extent>
|
|
class _LIBCPP_TEMPLATE_VIS span {
|
|
public:
|
|
// constants and types
|
|
using element_type = _Tp;
|
|
using value_type = remove_cv_t<_Tp>;
|
|
using size_type = size_t;
|
|
using difference_type = ptrdiff_t;
|
|
using pointer = _Tp *;
|
|
using const_pointer = const _Tp *;
|
|
using reference = _Tp &;
|
|
using const_reference = const _Tp &;
|
|
#ifdef _LIBCPP_SPAN_USE_POINTER_ITERATOR
|
|
using iterator = pointer;
|
|
#else
|
|
using iterator = __wrap_iter<pointer>;
|
|
#endif
|
|
using reverse_iterator = _VSTD::reverse_iterator<iterator>;
|
|
|
|
static constexpr size_type extent = _Extent;
|
|
|
|
// [span.cons], span constructors, copy, assignment, and destructor
|
|
template <size_t _Sz = _Extent, enable_if_t<_Sz == 0, nullptr_t> = nullptr>
|
|
_LIBCPP_INLINE_VISIBILITY constexpr span() noexcept : __data{nullptr} {}
|
|
|
|
constexpr span (const span&) noexcept = default;
|
|
constexpr span& operator=(const span&) noexcept = default;
|
|
|
|
template <class _It,
|
|
enable_if_t<contiguous_iterator<_It> &&
|
|
is_convertible_v<remove_reference_t<iter_reference_t<_It>>(*)[], element_type (*)[]>,
|
|
nullptr_t> = nullptr>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr explicit span(_It __first, size_type __count)
|
|
: __data{_VSTD::to_address(__first)} {
|
|
(void)__count;
|
|
_LIBCPP_ASSERT(_Extent == __count, "size mismatch in span's constructor (iterator, len)");
|
|
}
|
|
|
|
template <
|
|
class _It, class _End,
|
|
enable_if_t<is_convertible_v<remove_reference_t<iter_reference_t<_It> > (*)[], element_type (*)[]> &&
|
|
contiguous_iterator<_It> && sized_sentinel_for<_End, _It> && !is_convertible_v<_End, size_t>,
|
|
nullptr_t> = nullptr>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr explicit span(_It __first, _End __last) : __data{_VSTD::to_address(__first)} {
|
|
(void)__last;
|
|
_LIBCPP_ASSERT((__last - __first >= 0), "invalid range in span's constructor (iterator, sentinel)");
|
|
_LIBCPP_ASSERT(__last - __first == _Extent,
|
|
"invalid range in span's constructor (iterator, sentinel): last - first != extent");
|
|
}
|
|
|
|
_LIBCPP_INLINE_VISIBILITY constexpr span(type_identity_t<element_type> (&__arr)[_Extent]) noexcept : __data{__arr} {}
|
|
|
|
template <class _OtherElementType,
|
|
enable_if_t<is_convertible_v<_OtherElementType(*)[], element_type (*)[]>, nullptr_t> = nullptr>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr span(array<_OtherElementType, _Extent>& __arr) noexcept : __data{__arr.data()} {}
|
|
|
|
template <class _OtherElementType,
|
|
enable_if_t<is_convertible_v<const _OtherElementType(*)[], element_type (*)[]>, nullptr_t> = nullptr>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr span(const array<_OtherElementType, _Extent>& __arr) noexcept : __data{__arr.data()} {}
|
|
|
|
#if defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
|
|
template <class _Container>
|
|
requires __span_compatible_range<_Container, element_type>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr explicit span(_Container& __c) : __data{std::data(__c)} {
|
|
_LIBCPP_ASSERT(std::size(__c) == _Extent, "size mismatch in span's constructor (range)");
|
|
}
|
|
template <class _Container>
|
|
requires __span_compatible_range<const _Container, element_type>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr explicit span(const _Container& __c) : __data{std::data(__c)} {
|
|
_LIBCPP_ASSERT(std::size(__c) == _Extent, "size mismatch in span's constructor (range)");
|
|
}
|
|
#else
|
|
template <__span_compatible_range<element_type> _Range>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr explicit span(_Range&& __r) : __data{ranges::data(__r)} {
|
|
_LIBCPP_ASSERT(ranges::size(__r) == _Extent, "size mismatch in span's constructor (range)");
|
|
}
|
|
#endif
|
|
|
|
template <class _OtherElementType>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr span(const span<_OtherElementType, _Extent>& __other,
|
|
enable_if_t<
|
|
is_convertible_v<_OtherElementType(*)[], element_type (*)[]>,
|
|
nullptr_t> = nullptr)
|
|
: __data{__other.data()} {}
|
|
|
|
template <class _OtherElementType>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr explicit span(const span<_OtherElementType, dynamic_extent>& __other,
|
|
enable_if_t<
|
|
is_convertible_v<_OtherElementType(*)[], element_type (*)[]>,
|
|
nullptr_t> = nullptr) noexcept
|
|
: __data{__other.data()} { _LIBCPP_ASSERT(_Extent == __other.size(), "size mismatch in span's constructor (other span)"); }
|
|
|
|
|
|
// ~span() noexcept = default;
|
|
|
|
template <size_t _Count>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr span<element_type, _Count> first() const noexcept
|
|
{
|
|
static_assert(_Count <= _Extent, "Count out of range in span::first()");
|
|
return span<element_type, _Count>{data(), _Count};
|
|
}
|
|
|
|
template <size_t _Count>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr span<element_type, _Count> last() const noexcept
|
|
{
|
|
static_assert(_Count <= _Extent, "Count out of range in span::last()");
|
|
return span<element_type, _Count>{data() + size() - _Count, _Count};
|
|
}
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr span<element_type, dynamic_extent> first(size_type __count) const noexcept
|
|
{
|
|
_LIBCPP_ASSERT(__count <= size(), "Count out of range in span::first(count)");
|
|
return {data(), __count};
|
|
}
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr span<element_type, dynamic_extent> last(size_type __count) const noexcept
|
|
{
|
|
_LIBCPP_ASSERT(__count <= size(), "Count out of range in span::last(count)");
|
|
return {data() + size() - __count, __count};
|
|
}
|
|
|
|
template <size_t _Offset, size_t _Count = dynamic_extent>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr auto subspan() const noexcept
|
|
-> span<element_type, _Count != dynamic_extent ? _Count : _Extent - _Offset>
|
|
{
|
|
static_assert(_Offset <= _Extent, "Offset out of range in span::subspan()");
|
|
static_assert(_Count == dynamic_extent || _Count <= _Extent - _Offset, "Offset + count out of range in span::subspan()");
|
|
|
|
using _ReturnType = span<element_type, _Count != dynamic_extent ? _Count : _Extent - _Offset>;
|
|
return _ReturnType{data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count};
|
|
}
|
|
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr span<element_type, dynamic_extent>
|
|
subspan(size_type __offset, size_type __count = dynamic_extent) const noexcept
|
|
{
|
|
_LIBCPP_ASSERT(__offset <= size(), "Offset out of range in span::subspan(offset, count)");
|
|
_LIBCPP_ASSERT(__count <= size() || __count == dynamic_extent, "Count out of range in span::subspan(offset, count)");
|
|
if (__count == dynamic_extent)
|
|
return {data() + __offset, size() - __offset};
|
|
_LIBCPP_ASSERT(__count <= size() - __offset, "Offset + count out of range in span::subspan(offset, count)");
|
|
return {data() + __offset, __count};
|
|
}
|
|
|
|
_LIBCPP_INLINE_VISIBILITY constexpr size_type size() const noexcept { return _Extent; }
|
|
_LIBCPP_INLINE_VISIBILITY constexpr size_type size_bytes() const noexcept { return _Extent * sizeof(element_type); }
|
|
[[nodiscard]] _LIBCPP_INLINE_VISIBILITY constexpr bool empty() const noexcept { return _Extent == 0; }
|
|
|
|
_LIBCPP_INLINE_VISIBILITY constexpr reference operator[](size_type __idx) const noexcept
|
|
{
|
|
_LIBCPP_ASSERT(__idx < size(), "span<T,N>[] index out of bounds");
|
|
return __data[__idx];
|
|
}
|
|
|
|
_LIBCPP_INLINE_VISIBILITY constexpr reference front() const noexcept
|
|
{
|
|
_LIBCPP_ASSERT(!empty(), "span<T, N>::front() on empty span");
|
|
return __data[0];
|
|
}
|
|
|
|
_LIBCPP_INLINE_VISIBILITY constexpr reference back() const noexcept
|
|
{
|
|
_LIBCPP_ASSERT(!empty(), "span<T, N>::back() on empty span");
|
|
return __data[size()-1];
|
|
}
|
|
|
|
_LIBCPP_INLINE_VISIBILITY constexpr pointer data() const noexcept { return __data; }
|
|
|
|
// [span.iter], span iterator support
|
|
_LIBCPP_INLINE_VISIBILITY constexpr iterator begin() const noexcept {
|
|
#ifdef _LIBCPP_SPAN_USE_POINTER_ITERATOR
|
|
return iterator(data());
|
|
#else
|
|
return iterator(this, data());
|
|
#endif
|
|
}
|
|
_LIBCPP_INLINE_VISIBILITY constexpr iterator end() const noexcept {
|
|
#ifdef _LIBCPP_SPAN_USE_POINTER_ITERATOR
|
|
return iterator(data() + size());
|
|
#else
|
|
return iterator(this, data() + size());
|
|
#endif
|
|
}
|
|
_LIBCPP_INLINE_VISIBILITY constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); }
|
|
_LIBCPP_INLINE_VISIBILITY constexpr reverse_iterator rend() const noexcept { return reverse_iterator(begin()); }
|
|
|
|
_LIBCPP_INLINE_VISIBILITY span<const byte, _Extent * sizeof(element_type)> __as_bytes() const noexcept
|
|
{ return span<const byte, _Extent * sizeof(element_type)>{reinterpret_cast<const byte *>(data()), size_bytes()}; }
|
|
|
|
_LIBCPP_INLINE_VISIBILITY span<byte, _Extent * sizeof(element_type)> __as_writable_bytes() const noexcept
|
|
{ return span<byte, _Extent * sizeof(element_type)>{reinterpret_cast<byte *>(data()), size_bytes()}; }
|
|
|
|
private:
|
|
pointer __data;
|
|
|
|
};
|
|
|
|
|
|
template <typename _Tp>
|
|
class _LIBCPP_TEMPLATE_VIS span<_Tp, dynamic_extent> {
|
|
private:
|
|
|
|
public:
|
|
// constants and types
|
|
using element_type = _Tp;
|
|
using value_type = remove_cv_t<_Tp>;
|
|
using size_type = size_t;
|
|
using difference_type = ptrdiff_t;
|
|
using pointer = _Tp *;
|
|
using const_pointer = const _Tp *;
|
|
using reference = _Tp &;
|
|
using const_reference = const _Tp &;
|
|
#ifdef _LIBCPP_SPAN_USE_POINTER_ITERATOR
|
|
using iterator = pointer;
|
|
#else
|
|
using iterator = __wrap_iter<pointer>;
|
|
#endif
|
|
using reverse_iterator = _VSTD::reverse_iterator<iterator>;
|
|
|
|
static constexpr size_type extent = dynamic_extent;
|
|
|
|
// [span.cons], span constructors, copy, assignment, and destructor
|
|
_LIBCPP_INLINE_VISIBILITY constexpr span() noexcept : __data{nullptr}, __size{0} {}
|
|
|
|
constexpr span (const span&) noexcept = default;
|
|
constexpr span& operator=(const span&) noexcept = default;
|
|
|
|
template <class _It,
|
|
enable_if_t<contiguous_iterator<_It> &&
|
|
is_convertible_v<remove_reference_t<iter_reference_t<_It> > (*)[], element_type (*)[]>,
|
|
nullptr_t> = nullptr>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr span(_It __first, size_type __count)
|
|
: __data{_VSTD::to_address(__first)}, __size{__count} {}
|
|
|
|
template <
|
|
class _It, class _End,
|
|
enable_if_t<is_convertible_v<remove_reference_t<iter_reference_t<_It> > (*)[], element_type (*)[]> &&
|
|
contiguous_iterator<_It> && sized_sentinel_for<_End, _It> && !is_convertible_v<_End, size_t>,
|
|
nullptr_t> = nullptr>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr span(_It __first, _End __last)
|
|
: __data(_VSTD::to_address(__first)), __size(__last - __first) {}
|
|
|
|
template <size_t _Sz>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr span(type_identity_t<element_type> (&__arr)[_Sz]) noexcept : __data{__arr}, __size{_Sz} {}
|
|
|
|
template <class _OtherElementType, size_t _Sz,
|
|
enable_if_t<is_convertible_v<_OtherElementType(*)[], element_type (*)[]>, nullptr_t> = nullptr>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr span(array<_OtherElementType, _Sz>& __arr) noexcept : __data{__arr.data()}, __size{_Sz} {}
|
|
|
|
template <class _OtherElementType, size_t _Sz,
|
|
enable_if_t<is_convertible_v<const _OtherElementType(*)[], element_type (*)[]>, nullptr_t> = nullptr>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr span(const array<_OtherElementType, _Sz>& __arr) noexcept : __data{__arr.data()}, __size{_Sz} {}
|
|
|
|
#if defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
|
|
template <class _Container>
|
|
requires __span_compatible_range<_Container, element_type>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr span(_Container& __c) : __data(std::data(__c)), __size{std::size(__c)} {}
|
|
template <class _Container>
|
|
requires __span_compatible_range<const _Container, element_type>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr span(const _Container& __c) : __data(std::data(__c)), __size{std::size(__c)} {}
|
|
#else
|
|
template <__span_compatible_range<element_type> _Range>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr span(_Range&& __r) : __data(ranges::data(__r)), __size{ranges::size(__r)} {}
|
|
#endif
|
|
|
|
template <class _OtherElementType, size_t _OtherExtent>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr span(const span<_OtherElementType, _OtherExtent>& __other,
|
|
enable_if_t<
|
|
is_convertible_v<_OtherElementType(*)[], element_type (*)[]>,
|
|
nullptr_t> = nullptr) noexcept
|
|
: __data{__other.data()}, __size{__other.size()} {}
|
|
|
|
// ~span() noexcept = default;
|
|
|
|
template <size_t _Count>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr span<element_type, _Count> first() const noexcept
|
|
{
|
|
_LIBCPP_ASSERT(_Count <= size(), "Count out of range in span::first()");
|
|
return span<element_type, _Count>{data(), _Count};
|
|
}
|
|
|
|
template <size_t _Count>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr span<element_type, _Count> last() const noexcept
|
|
{
|
|
_LIBCPP_ASSERT(_Count <= size(), "Count out of range in span::last()");
|
|
return span<element_type, _Count>{data() + size() - _Count, _Count};
|
|
}
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr span<element_type, dynamic_extent> first(size_type __count) const noexcept
|
|
{
|
|
_LIBCPP_ASSERT(__count <= size(), "Count out of range in span::first(count)");
|
|
return {data(), __count};
|
|
}
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr span<element_type, dynamic_extent> last (size_type __count) const noexcept
|
|
{
|
|
_LIBCPP_ASSERT(__count <= size(), "Count out of range in span::last(count)");
|
|
return {data() + size() - __count, __count};
|
|
}
|
|
|
|
template <size_t _Offset, size_t _Count = dynamic_extent>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
constexpr span<element_type, _Count> subspan() const noexcept
|
|
{
|
|
_LIBCPP_ASSERT(_Offset <= size(), "Offset out of range in span::subspan()");
|
|
_LIBCPP_ASSERT(_Count == dynamic_extent || _Count <= size() - _Offset, "Offset + count out of range in span::subspan()");
|
|
return span<element_type, _Count>{data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count};
|
|
}
|
|
|
|
constexpr span<element_type, dynamic_extent>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
subspan(size_type __offset, size_type __count = dynamic_extent) const noexcept
|
|
{
|
|
_LIBCPP_ASSERT(__offset <= size(), "Offset out of range in span::subspan(offset, count)");
|
|
_LIBCPP_ASSERT(__count <= size() || __count == dynamic_extent, "count out of range in span::subspan(offset, count)");
|
|
if (__count == dynamic_extent)
|
|
return {data() + __offset, size() - __offset};
|
|
_LIBCPP_ASSERT(__count <= size() - __offset, "Offset + count out of range in span::subspan(offset, count)");
|
|
return {data() + __offset, __count};
|
|
}
|
|
|
|
_LIBCPP_INLINE_VISIBILITY constexpr size_type size() const noexcept { return __size; }
|
|
_LIBCPP_INLINE_VISIBILITY constexpr size_type size_bytes() const noexcept { return __size * sizeof(element_type); }
|
|
[[nodiscard]] _LIBCPP_INLINE_VISIBILITY constexpr bool empty() const noexcept { return __size == 0; }
|
|
|
|
_LIBCPP_INLINE_VISIBILITY constexpr reference operator[](size_type __idx) const noexcept
|
|
{
|
|
_LIBCPP_ASSERT(__idx < size(), "span<T>[] index out of bounds");
|
|
return __data[__idx];
|
|
}
|
|
|
|
_LIBCPP_INLINE_VISIBILITY constexpr reference front() const noexcept
|
|
{
|
|
_LIBCPP_ASSERT(!empty(), "span<T>[].front() on empty span");
|
|
return __data[0];
|
|
}
|
|
|
|
_LIBCPP_INLINE_VISIBILITY constexpr reference back() const noexcept
|
|
{
|
|
_LIBCPP_ASSERT(!empty(), "span<T>[].back() on empty span");
|
|
return __data[size()-1];
|
|
}
|
|
|
|
|
|
_LIBCPP_INLINE_VISIBILITY constexpr pointer data() const noexcept { return __data; }
|
|
|
|
// [span.iter], span iterator support
|
|
_LIBCPP_INLINE_VISIBILITY constexpr iterator begin() const noexcept {
|
|
#ifdef _LIBCPP_SPAN_USE_POINTER_ITERATOR
|
|
return iterator(data());
|
|
#else
|
|
return iterator(this, data());
|
|
#endif
|
|
}
|
|
_LIBCPP_INLINE_VISIBILITY constexpr iterator end() const noexcept {
|
|
#ifdef _LIBCPP_SPAN_USE_POINTER_ITERATOR
|
|
return iterator(data() + size());
|
|
#else
|
|
return iterator(this, data() + size());
|
|
#endif
|
|
}
|
|
_LIBCPP_INLINE_VISIBILITY constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); }
|
|
_LIBCPP_INLINE_VISIBILITY constexpr reverse_iterator rend() const noexcept { return reverse_iterator(begin()); }
|
|
|
|
_LIBCPP_INLINE_VISIBILITY span<const byte, dynamic_extent> __as_bytes() const noexcept
|
|
{ return {reinterpret_cast<const byte *>(data()), size_bytes()}; }
|
|
|
|
_LIBCPP_INLINE_VISIBILITY span<byte, dynamic_extent> __as_writable_bytes() const noexcept
|
|
{ return {reinterpret_cast<byte *>(data()), size_bytes()}; }
|
|
|
|
private:
|
|
pointer __data;
|
|
size_type __size;
|
|
};
|
|
|
|
template <class _Tp, size_t _Extent>
|
|
inline constexpr bool ranges::enable_borrowed_range<span<_Tp, _Extent> > = true;
|
|
|
|
template <class _ElementType, size_t _Extent>
|
|
inline constexpr bool ranges::enable_view<span<_ElementType, _Extent>> = true;
|
|
|
|
// as_bytes & as_writable_bytes
|
|
template <class _Tp, size_t _Extent>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
auto as_bytes(span<_Tp, _Extent> __s) noexcept
|
|
-> decltype(__s.__as_bytes())
|
|
{ return __s.__as_bytes(); }
|
|
|
|
template <class _Tp, size_t _Extent>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
auto as_writable_bytes(span<_Tp, _Extent> __s) noexcept
|
|
-> enable_if_t<!is_const_v<_Tp>, decltype(__s.__as_writable_bytes())>
|
|
{ return __s.__as_writable_bytes(); }
|
|
|
|
#if _LIBCPP_STD_VER > 17
|
|
template<contiguous_iterator _It, class _EndOrSize>
|
|
span(_It, _EndOrSize) -> span<remove_reference_t<iter_reference_t<_It>>>;
|
|
#endif // _LIBCPP_STD_VER > 17
|
|
|
|
template<class _Tp, size_t _Sz>
|
|
span(_Tp (&)[_Sz]) -> span<_Tp, _Sz>;
|
|
|
|
template<class _Tp, size_t _Sz>
|
|
span(array<_Tp, _Sz>&) -> span<_Tp, _Sz>;
|
|
|
|
template<class _Tp, size_t _Sz>
|
|
span(const array<_Tp, _Sz>&) -> span<const _Tp, _Sz>;
|
|
|
|
#if defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
|
|
template<class _Container>
|
|
span(_Container&) -> span<typename _Container::value_type>;
|
|
|
|
template<class _Container>
|
|
span(const _Container&) -> span<const typename _Container::value_type>;
|
|
#else
|
|
template<ranges::contiguous_range _Range>
|
|
span(_Range&&) -> span<remove_reference_t<ranges::range_reference_t<_Range>>>;
|
|
#endif
|
|
|
|
#endif // _LIBCPP_STD_VER > 17
|
|
|
|
_LIBCPP_END_NAMESPACE_STD
|
|
|
|
_LIBCPP_POP_MACROS
|
|
|
|
#endif // _LIBCPP_SPAN
|