70# if !defined(TCB_SPAN_THROW_ON_CONTRACT_VIOLATION) && \
71 !defined(TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION) && \
72 !defined(TCB_SPAN_NO_CONTRACT_CHECKING)
73# if defined(NDEBUG) || !defined(TCB_SPAN_HAVE_CPP14)
74# define TCB_SPAN_NO_CONTRACT_CHECKING
76# define TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION
80# if defined(TCB_SPAN_THROW_ON_CONTRACT_VIOLATION)
81 struct contract_violation_error : std::logic_error {
82 explicit contract_violation_error(
const char* msg)
83 : std::logic_error(msg) {}
86 inline void contract_violation(
const char* msg) {
87 throw contract_violation_error(msg);
90# elif defined(TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION)
91 [[noreturn]]
inline void contract_violation(
const char* ) {
96# if !defined(TCB_SPAN_NO_CONTRACT_CHECKING)
97# define TCB_SPAN_STRINGIFY(cond) # cond
98# define TCB_SPAN_EXPECT(cond) \
100 : contract_violation( \
101 "Expected " TCB_SPAN_STRINGIFY(cond))
103# define TCB_SPAN_EXPECT(cond)
106# if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_inline_variables)
107# define TCB_SPAN_INLINE_VAR inline
109# define TCB_SPAN_INLINE_VAR
112# if defined(TCB_SPAN_HAVE_CPP14) || \
113 (defined(__cpp_constexpr) && __cpp_constexpr >= 201304)
114# define TCB_SPAN_HAVE_CPP14_CONSTEXPR
117# if defined(TCB_SPAN_HAVE_CPP14_CONSTEXPR)
118# define TCB_SPAN_CONSTEXPR14 constexpr
120# define TCB_SPAN_CONSTEXPR14
123# if defined(TCB_SPAN_HAVE_CPP14_CONSTEXPR) && \
124 (!defined(_MSC_VER) || _MSC_VER > 1900)
125# define TCB_SPAN_CONSTEXPR_ASSIGN constexpr
127# define TCB_SPAN_CONSTEXPR_ASSIGN
130# if defined(TCB_SPAN_NO_CONTRACT_CHECKING)
131# define TCB_SPAN_CONSTEXPR11 constexpr
133# define TCB_SPAN_CONSTEXPR11 TCB_SPAN_CONSTEXPR14
136# if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_deduction_guides)
137# define TCB_SPAN_HAVE_DEDUCTION_GUIDES
140# if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_byte)
141# define TCB_SPAN_HAVE_STD_BYTE
144# if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_array_constexpr)
145# define TCB_SPAN_HAVE_CONSTEXPR_STD_ARRAY_ETC
148# if defined(TCB_SPAN_HAVE_CONSTEXPR_STD_ARRAY_ETC)
149# define TCB_SPAN_ARRAY_CONSTEXPR constexpr
151# define TCB_SPAN_ARRAY_CONSTEXPR
154# ifdef TCB_SPAN_HAVE_STD_BYTE
155 using byte = std::byte;
160# if defined(TCB_SPAN_HAVE_CPP17)
161# define TCB_SPAN_NODISCARD [[nodiscard]]
163# define TCB_SPAN_NODISCARD
168 template<
typename ElementType, std::
size_t Extent = dynamic_extent>
173 template<
typename E, std::
size_t S>
174 struct span_storage {
175 constexpr span_storage() noexcept = default;
177 constexpr span_storage(E* ptr,
std::
size_t ) noexcept
181 static constexpr std::size_t size = S;
186 constexpr span_storage() noexcept = default;
188 constexpr span_storage(E* ptr,
std::
size_t size) noexcept
189 : ptr(ptr), size(size) {}
192 std::size_t size = 0;
196# if defined(TCB_SPAN_HAVE_CPP17) || \
197 defined(__cpp_lib_nonmember_container_access)
202 constexpr auto size(
const C& c) ->
decltype(c.size()) {
206 template<
class T, std::
size_t N>
207 constexpr std::size_t size(
const T (&)[N])
noexcept {
212 constexpr auto data(C& c) ->
decltype(c.data()) {
217 constexpr auto data(
const C& c) ->
decltype(c.data()) {
221 template<
class T, std::
size_t N>
222 constexpr T* data(T (&array)[N])
noexcept {
227 constexpr const E* data(std::initializer_list<E> il)
noexcept {
232# if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_void_t)
235 template<
typename...>
240 using uncvref_t =
typename std::remove_cv<
241 typename std::remove_reference<T>::type>::type;
244 struct is_span : std::false_type {};
246 template<
typename T, std::
size_t S>
247 struct is_span<span<
T,
S>> : std::true_type {};
250 struct is_std_array : std::false_type {};
252 template<
typename T, std::
size_t N>
253 struct is_std_array<
std::array<T, N>> : std::true_type {};
255 template<
typename,
typename =
void>
256 struct has_size_and_data : std::false_type {};
259 struct has_size_and_data<
260 T,
void_t<decltype(detail::size(std::declval<T>())),
261 decltype(detail::data(std::declval<T>()))>>
264 template<
typename C,
typename U = uncvref_t<C>>
265 struct is_container {
266 static constexpr bool value =
267 !is_span<U>::value && !is_std_array<U>::value &&
268 !std::is_array<U>::value && has_size_and_data<C>::value;
272 using remove_pointer_t =
typename std::remove_pointer<T>::type;
274 template<
typename,
typename,
typename =
void>
275 struct is_container_element_type_compatible : std::false_type {};
277 template<
typename T,
typename E>
278 struct is_container_element_type_compatible<
279 T,
E,
void_t<decltype(detail::data(std::declval<T>()))>>
280 : std::is_convertible<
281 remove_pointer_t<decltype(
282 detail::data(std::declval<T>()))> (*)[],
285 template<
typename,
typename =
size_t>
286 struct is_complete : std::false_type {};
289 struct is_complete<
T, decltype(sizeof(
T))> : std::true_type {};
293 template<
typename ElementType, std::
size_t Extent>
296 std::is_object<ElementType>::value,
297 "A span's ElementType must be an object type (not a "
298 "reference type or void)");
300 detail::is_complete<ElementType>::value,
301 "A span's ElementType must be a complete type (not a forward "
304 !std::is_abstract<ElementType>::value,
305 "A span's ElementType cannot be an abstract class type");
307 using storage_type = detail::span_storage<ElementType, Extent>;
311 using element_type = ElementType;
312 using value_type =
typename std::remove_cv<ElementType>::type;
313 using index_type = std::size_t;
314 using difference_type = std::ptrdiff_t;
315 using pointer = element_type*;
316 using const_pointer =
const element_type*;
317 using reference = element_type&;
318 using iterator = pointer;
319 using const_iterator = const_pointer;
320 using reverse_iterator = std::reverse_iterator<iterator>;
321 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
323 static constexpr index_type extent = Extent;
327 std::size_t
E = Extent,
328 typename std::enable_if<
330 constexpr span() noexcept {}
333 : storage_(ptr,
count) {
338 : storage_(first_elem, last_elem - first_elem) {
340 extent == dynamic_extent ||
341 last_elem - first_elem ==
342 static_cast<std::ptrdiff_t
>(extent));
346 std::size_t
N, std::size_t
E = Extent,
347 typename std::enable_if<
349 detail::is_container_element_type_compatible<
353 constexpr span(element_type (&arr)[N]) noexcept : storage_(arr, N) {}
356 std::size_t
N, std::size_t
E = Extent,
357 typename std::enable_if<
359 detail::is_container_element_type_compatible<
360 std::array<value_type, N>&,
364 : storage_(arr.data(), N) {}
367 std::size_t
N, std::size_t
E = Extent,
368 typename std::enable_if<
370 detail::is_container_element_type_compatible<
371 const std::array<value_type, N>&,
375 const std::array<value_type, N>& arr) noexcept
376 : storage_(arr.data(), N) {}
379 typename Container, std::size_t
E = Extent,
380 typename std::enable_if<
382 detail::is_container<Container>::value &&
383 detail::is_container_element_type_compatible<
384 Container&, ElementType>::value,
386 constexpr span(Container& cont)
387 : storage_(detail::data(cont), detail::size(cont)) {}
390 typename Container, std::size_t
E = Extent,
391 typename std::enable_if<
393 detail::is_container<Container>::value &&
394 detail::is_container_element_type_compatible<
395 const Container&, ElementType>::value,
397 constexpr span(
const Container& cont)
398 : storage_(detail::data(cont), detail::size(cont)) {}
400 constexpr span(
const span& other)
noexcept =
default;
403 typename OtherElementType, std::size_t OtherExtent,
404 typename std::enable_if<
407 OtherElementType (*)[],
408 ElementType (*)[]>::value,
411 const span<OtherElementType, OtherExtent>& other) noexcept
412 : storage_(other.data(), other.size()) {}
414 ~span() noexcept = default;
420 template<
std::
size_t Count>
423 return {data(),
Count};
426 template<std::
size_t Count>
429 return {data() + (size() -
Count), Count};
432 template<std::
size_t Offset, std::
size_t Count = dynamic_extent>
433 using subspan_return_t =
440 template<std::
size_t Offset, std::
size_t Count = dynamic_extent>
444 (Count == dynamic_extent || Offset + Count <= size()));
450 index_type count)
const {
452 return {data(),
count};
456 index_type count)
const {
458 return {data() + (size() -
count), count};
462 index_type offset, index_type count = dynamic_extent)
const {
465 (count == dynamic_extent || offset + count <= size()));
466 return {data() + offset,
471 [[nodiscard]]
constexpr index_type size() const noexcept {
return storage_.size; }
473 [[nodiscard]]
constexpr index_type size_bytes() const noexcept {
474 return size() *
sizeof(element_type);
484 return *(data() + idx);
494 return *(data() + (size() - 1));
497 [[nodiscard]]
constexpr pointer data() const noexcept {
return storage_.ptr; }
500 [[nodiscard]]
constexpr iterator
begin() const noexcept {
return data(); }
502 [[nodiscard]]
constexpr iterator
end() const noexcept {
return data() + size(); }
504 [[nodiscard]]
constexpr const_iterator cbegin() const noexcept {
return begin(); }
506 [[nodiscard]]
constexpr const_iterator cend() const noexcept {
return end(); }
509 return reverse_iterator(
end());
513 return reverse_iterator(
begin());
518 return const_reverse_iterator(cend());
522 return const_reverse_iterator(cbegin());
525 friend constexpr iterator
begin(span s)
noexcept {
return s.begin(); }
527 friend constexpr iterator
end(span s)
noexcept {
return s.end(); }
530 storage_type storage_{};
533# ifdef TCB_SPAN_HAVE_DEDUCTION_GUIDES
536 template<
class T,
size_t N>
537 span(T (&)[N])->span<
T,
N>;
539 template<
class T,
size_t N>
540 span(std::array<T, N>&)->span<
T,
N>;
542 template<
class T,
size_t N>
543 span(
const std::array<T, N>&)->span<
const T,
N>;
545 template<
class Container>
546 span(Container&)->span<
typename Container::value_type>;
548 template<
class Container>
549 span(
const Container&)->span<
const typename Container::value_type>;
553 template<
typename ElementType, std::
size_t Extent>
555 span<ElementType, Extent> s)
noexcept {
559 template<
typename T, std::
size_t N>
564 template<
typename T, std::
size_t N>
566 std::array<T, N>& arr)
noexcept {
570 template<
typename T, std::
size_t N>
572 const std::array<T, N>& arr)
noexcept {
576 template<
typename Container>
577 constexpr span<typename Container::value_type>
make_span(Container& cont) {
581 template<
typename Container>
582 constexpr span<const typename Container::value_type>
make_span(
583 const Container& cont) {
591 template<
typename T, std::
size_t X,
typename U, std::
size_t Y>
593 if(lhs.size() != rhs.size()) {
597 for(std::size_t i = 0; i < lhs.size(); i++) {
598 if(lhs[i] != rhs[i]) {
606 template<
typename T, std::
size_t X,
typename U, std::
size_t Y>
608 return !(lhs == rhs);
611 template<
typename T, std::
size_t X,
typename U, std::
size_t Y>
614 const std::size_t size =
615 lhs.size() < rhs.size() ? lhs.size() : rhs.size();
617 for(std::size_t i = 0; i < size; i++) {
618 if(lhs[i] < rhs[i]) {
621 if(lhs[i] > rhs[i]) {
625 return lhs.size() < rhs.size();
628 template<
typename T, std::
size_t X,
typename U, std::
size_t Y>
633 template<
typename T, std::
size_t X,
typename U, std::
size_t Y>
638 template<
typename T, std::
size_t X,
typename U, std::
size_t Y>
643 template<
typename ElementType, std::
size_t Extent>
645 ((Extent == dynamic_extent) ? dynamic_extent
646 : sizeof(ElementType) * Extent)>
648 return {reinterpret_cast<const
byte*>(s.data()), s.size_bytes()};
652 class ElementType,
size_t Extent,
653 typename std::enable_if<
654 !std::is_const<ElementType>::value,
int>::type = 0>
655 span<byte, ((Extent == dynamic_extent) ? dynamic_extent
656 : sizeof(ElementType) * Extent)>
658 return {reinterpret_cast<
byte*>(s.data()), s.size_bytes()};
661 template<std::
size_t N,
typename E, std::
size_t S>
662 constexpr auto get(span<E, S> s) ->
decltype(s[N]) {