...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
This header <boost/core/span.hpp> provides class template span
, which is a view over a sequence of
objects. It implements the C++20 standard library std::span
facility. This implementation supports C++11 and higher.
In addition to referencing the sequence of objects, the span knows the count of objects. There are two kinds of spans:
span<T>
or span<T, dynamic_extent>
)
span<T, N>
)
Dynamic size spans have a count that can be a value known at run time. Static size spans have a count that must be known at compile time.
The following snippet shows a function to compute a SHA1 hash whose parameters and return type use spans.
auto sha1(boost::span<const unsigned char> input, boost::span<unsigned char, SHA_DIGEST_LENGTH> ouput) { SHA_CTX context; SHA1_Init(&context); SHA1_Update(&context, input.data(), input.size()); SHA1_Final(output.data(), &context); return output; }
namespace boost { constexpr std::size_t dynamic_extent = -1; template<class T, std::size_t E = dynamic_extent> class span { public: typedef T element_type; typedef std::remove_cv_t<T> value_type; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef T* iterator; typedef const T* const_iterator; typedef std::reverse_iterator<T*> reverse_iterator; typedef std::reverse_iterator<const T*> const_reverse_iterator; static constexpr std::size_t extent = E; constexpr span() noexcept; explicit(E != dynamic_extent) template<class I> constexpr span(I* f, size_type c); explicit(E != dynamic_extent) template<class I, class L> constexpr span(I* f, L* l); template<std::size_t N> constexpr span(type_identity_t<T> (&a)[N]); template<class U, std::size_t N> constexpr span(std::array<U, N>& a) noexcept; template<class U, std::size_t N> constexpr span(const std::array<U, N>& a) noexcept; explicit(E != dynamic_extent) template<class R> constexpr span(R&& r); explicit(E != dynamic_extent && N == dynamic_extent) template<class U, std::size_t N> constexpr span(const span<U, N>& s) noexcept; template<std::size_t C> constexpr span<T, C> first() const; template<std::size_t C> constexpr span<T, C> last() const; template<std::size_t O, std::size_t C = dynamic_extent> constexpr span<T, see below> subspan() const; constexpr span<T, dynamic_extent> first(size_type c) const; constexpr span<T, dynamic_extent> last(size_type c) const; constexpr span<T, dynamic_extent> subspan(size_type o, size_type c = dynamic_extent) const; constexpr size_type size() const noexcept; constexpr size_type size_bytes() const noexcept; constexpr bool empty() const noexcept; constexpr reference operator[](size_type i) const; constexpr reference front() const; constexpr reference back() const; constexpr pointer data() const noexcept; constexpr iterator begin() const noexcept; constexpr iterator end() const noexcept; constexpr reverse_iterator rbegin() const noexcept; constexpr reverse_iterator rend() const noexcept; constexpr const_iterator cbegin() const noexcept; constexpr const_iterator cend() const noexcept; constexpr const_reverse_iterator crbegin() const noexcept; constexpr const_reverse_iterator crend() const noexcept; }; template<class I, class L> span(I*, L) -> span<I>; template<class T, std::size_t N> span(T(&)[N]) -> span<T, N>; template<class T, std::size_t N> span(std::array<T, N>&) -> span<T, N>; template<class T, std::size_t N> span(const std::array<T, N>&) -> span<const T, N>; template<class R> span(R&&) -> span<remove_pointer_t<iterator_t<R> > >; template<class T, std::size_t E> span<const std::byte, E == dynamic_extent ? dynamic_extent : sizeof(T) * E> as_bytes(span<T, E> s) noexcept; template<class T, std::size_t E> span<std::byte, E == dynamic_extent ? dynamic_extent : sizeof(T) * E> as_writable_bytes(span<T, E> s) noexcept; } /* boost */
constexpr span() noexcept;
E ==
dynamic_extent ||
E ==
0
is true
.
size()
== 0
&& data() ==
nullptr
.
explicit(E != dynamic_extent)
template<class I> constexpr
span(I* f, size_type c);
is_convertible_v<I(*)[], T(*)[]>
is true
.
[f, f
+ c)
is a valid range.
E
is
not equal to dynamic_extent
,
then c
is equal to E
.
span
with data f
and size c
.
Nothing.
explicit(E != dynamic_extent)
template<class I, class L> constexpr span(I* f, L* l);
is_convertible_v<I(*)[], T(*)[]>
is true
.
E
is
not equal to dynamic_extent
,
then l - f
is equal to E
.
[f, l)
is a valid range.
span
with data f
and size l - f
.
Nothing.
template<std::size_t N> constexpr
span(type_identity_t<T> (&a)[N]);
E ==
dynamic_extent ||
E ==
N
is true
.
Constructs a span
that is a view over the supplied array.
size()
== N
&& data() ==
&a[0]
is true
.
template<class U, std::size_t
N>
constexpr span(std::array<U, N>& a) noexcept;
E ==
dynamic_extent || E
== N
is true
, and
U(*)[]
is convertible to T(*)[]
.
span
that is a view over the supplied array.
size()
== N
&& data() ==
a.data()
is true
.
template<class U, std::size_t
N>
constexpr span(const std::array<U, N>&
a)
noexcept;
E ==
dynamic_extent || E
== N
is true
, and
U(*)[]
is convertible to T(*)[]
.
span
that is a view over the supplied array.
size()
== N
&& data() ==
a.data()
is true
.
explicit(E != dynamic_extent)
template<class R> constexpr
span(R&&
r);
is_lvalue_reference_v<R> ||
is_const_v<T>
is true
remove_cvref_t<R>
is not a specialization
of span
,
remove_cvref_t<R>
is not a specialization
of array
,
is_array_v<remove_cvref_t<R>>
is false
,
data(r)
is well-formed and is_convertible_v<remove_pointer_t<iterator_t<R> >(*)[],
T(*)[]>
is true
, and
r.size()
is well-formed and is_convertible_v<decltype(declval<R&>().size()), size_t>
is true
.
span
with data data(r)
and size r.size()
.
What and when data(r) and r.size() throw.
explicit(E != dynamic_extent &&
N ==
dynamic_extent)
template<class U, std::size_t
N>
constexpr span(const span<U, N>&
s)
noexcept;
E ==
dynamic_extent || N
== dynamic_extent
|| E
== N
is true
, and
is_convertible_v<U(*)[], T(*)[]>
is true
.
E
is not
equal to dynamic_extent
,
then s.size()
is equal to E
.
Constructs a span
that is a view over the range [s.data(),
s.data()
+ s.size())
.
size()
== s.size() &&
data()
== s.data()
.
template<std::size_t C> constexpr
span<T, C> first() const;
C <=
E
is true
.
C <=
size()
is true
.
Equivalent to return
R{data(),
C};
where R
is
the return type.
template<std::size_t C> constexpr
span<T, C> last() const;
C <=
E
is true
.
C <=
size()
is true
.
Equivalent to return
R{data()
+ (size()
- C), C};
where R
is the return type.
template<std::size_t O, std::size_t
C =
dynamic_extent>
constexpr span<T, see below>
subspan()
const;
O <=
E &&
(C
== dynamic_extent
|| C
<= E
- O)
is true
.
O <=
size()
&& (C ==
dynamic_extent ||
C <=
size()
- O)
is true
.
Equivalent to return
span<T,
see below>(data() +
O,
C !=
dynamic_extent ?
C :
size()
- O);
.
The second template argument of the returned span type is:
C !=
dynamic_extent ?
C :
(E
!= dynamic_extent
? E
- O
: dynamic_extent)
constexpr span<T, dynamic_extent> first(size_type
c)
const;
c <=
size()
is true
.
Equivalent to: return
{data(), c};
constexpr span<T, dynamic_extent> last(size_type
c)
const;
c <=
size()
is true
.
Equivalent to: return
{data() +
(size() -
c),
c};
constexpr span<T, dynamic_extent> subspan(size_type
o,
size_type c
= dynamic_extent) const;
o <=
size()
&& (c ==
dynamic_extent ||
o +
c <=
size())
is true
.
Equivalent to: return
{data() +
o,
c ==
dynamic_extent ?
size()
- o
: c};
constexpr size_type
size()
const noexcept;
The number of elements in the span.
constexpr size_type
size_bytes()
const noexcept;
Equivalent to: return
size()
* sizeof(T);
constexpr bool
empty()
const noexcept;
Equivalent to: return
size()
== 0;
constexpr reference
operator[](size_type i) const;
i <
size()
is true
.
Equivalent to: return
*(data() +
i);
constexpr reference
front()
const;
empty()
is false
.
Equivalent to: return
*data();
constexpr reference
back()
const;
empty()
is false
.
Equivalent to: return
*(data() +
(size() -
1);
constexpr pointer
data()
const noexcept;
A pointer to the first element in the span.
constexpr iterator
begin()
const noexcept;
A constant iterator referring to the first element in the span.
If empty()
,
then it returns the same value as cend()
.
constexpr iterator
end()
const noexcept;
A constant iterator which is the past-the-end value.
constexpr reverse_iterator
rbegin()
const noexcept;
Equivalent to: return
reverse_iterator(end());
constexpr reverse_iterator
rend()
const noexcept;
Equivalent to: return
reverse_iterator(begin());
constexpr const_iterator
cbegin()
const noexcept;
A constant iterator referring to the first element in the span.
If empty()
,
then it returns the same value as cend()
.
constexpr const_iterator
cend()
const noexcept;
A constant iterator which is the past-the-end value.
constexpr const_reverse_iterator
crbegin()
const noexcept;
Equivalent to: return
const_reverse_iterator(cend());
constexpr const_reverse_iterator
crend()
const noexcept;
Equivalent to: return
const_reverse_iterator(cbegin());
template<class T, std::size_t
E>
span<const std::byte, E == dynamic_extent
? dynamic_extent
: sizeof(T) * E> as_bytes(span<T, E> s) noexcept;
Equivalent to: return
{reinterpret_cast<const
byte*>(s.data()),
s.size_bytes()};
.
template<class T, std::size_t
E>
span<std::byte, E == dynamic_extent ?
dynamic_extent :
sizeof(T) * E> as_writable_bytes(span<T, E> s) noexcept;
is_const_v<T>
is false
.
Equivalent to: return
R{reinterpret_cast<byte*>(s.data()),
s.size_bytes()};
where R
is
the return type.