35 #ifndef TCB_SPAN_HPP_INCLUDED
36 #define TCB_SPAN_HPP_INCLUDED
41 #include <type_traits>
43 #ifndef TCB_SPAN_NO_EXCEPTIONS
45 #if !(defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND))
46 #define TCB_SPAN_NO_EXCEPTIONS
50 #ifndef TCB_SPAN_NO_EXCEPTIONS
57 #ifndef TCB_SPAN_NAMESPACE_NAME
58 #define TCB_SPAN_NAMESPACE_NAME nonstd
61 #if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
62 #define TCB_SPAN_HAVE_CPP17
65 #if __cplusplus >= 201402L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L)
66 #define TCB_SPAN_HAVE_CPP14
69 namespace TCB_SPAN_NAMESPACE_NAME {
72 #if !defined(TCB_SPAN_THROW_ON_CONTRACT_VIOLATION) && !defined(TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION) && \
73 !defined(TCB_SPAN_NO_CONTRACT_CHECKING)
74 #if defined(NDEBUG) || !defined(TCB_SPAN_HAVE_CPP14)
75 #define TCB_SPAN_NO_CONTRACT_CHECKING
77 #define TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION
81 #if defined(TCB_SPAN_THROW_ON_CONTRACT_VIOLATION)
82 struct contract_violation_error : std::logic_error {
83 explicit contract_violation_error(
const char* msg)
84 : std::logic_error(msg) {}
87 inline void contract_violation(
const char* msg) {
throw contract_violation_error(msg); }
89 #elif defined(TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION)
90 [[noreturn]]
inline void contract_violation(
const char* ) { std::terminate(); }
93 #if !defined(TCB_SPAN_NO_CONTRACT_CHECKING)
94 #define TCB_SPAN_STRINGIFY(cond) #cond
95 #define TCB_SPAN_EXPECT(cond) cond ? (void)0 : contract_violation("Expected " TCB_SPAN_STRINGIFY(cond))
97 #define TCB_SPAN_EXPECT(cond)
100 #if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_inline_variables)
101 #define TCB_SPAN_INLINE_VAR inline
103 #define TCB_SPAN_INLINE_VAR
106 #if defined(TCB_SPAN_HAVE_CPP14) || (defined(__cpp_constexpr) && __cpp_constexpr >= 201304)
107 #define TCB_SPAN_HAVE_CPP14_CONSTEXPR
110 #if defined(TCB_SPAN_HAVE_CPP14_CONSTEXPR)
111 #define TCB_SPAN_CONSTEXPR14 constexpr
113 #define TCB_SPAN_CONSTEXPR14
116 #if defined(TCB_SPAN_HAVE_CPP14_CONSTEXPR) && (!defined(_MSC_VER) || _MSC_VER > 1900)
117 #define TCB_SPAN_CONSTEXPR_ASSIGN constexpr
119 #define TCB_SPAN_CONSTEXPR_ASSIGN
122 #if defined(TCB_SPAN_NO_CONTRACT_CHECKING)
123 #define TCB_SPAN_CONSTEXPR11 constexpr
125 #define TCB_SPAN_CONSTEXPR11 TCB_SPAN_CONSTEXPR14
128 #if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_deduction_guides)
129 #define TCB_SPAN_HAVE_DEDUCTION_GUIDES
132 #if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_byte)
133 #define TCB_SPAN_HAVE_STD_BYTE
136 #if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_array_constexpr)
137 #define TCB_SPAN_HAVE_CONSTEXPR_STD_ARRAY_ETC
140 #if defined(TCB_SPAN_HAVE_CONSTEXPR_STD_ARRAY_ETC)
141 #define TCB_SPAN_ARRAY_CONSTEXPR constexpr
143 #define TCB_SPAN_ARRAY_CONSTEXPR
146 #ifdef TCB_SPAN_HAVE_STD_BYTE
147 using byte = std::byte;
149 using byte =
unsigned char;
152 #if defined(TCB_SPAN_HAVE_CPP17)
153 #define TCB_SPAN_NODISCARD [[nodiscard]]
155 #define TCB_SPAN_NODISCARD
158 TCB_SPAN_INLINE_VAR constexpr std::size_t dynamic_extent = SIZE_MAX;
160 template <
typename ElementType, std::
size_t Extent = dynamic_extent>
class span;
171 static constexpr std::size_t size = S;
177 constexpr
span_storage(E* p_ptr, std::size_t p_size) noexcept
182 std::size_t size = 0;
186 #if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_nonmember_container_access)
190 template <
class C> constexpr
auto size(
const C& c) -> decltype(c.size()) {
return c.size(); }
192 template <
class T, std::
size_t N> constexpr std::size_t size(
const T (&)[N]) noexcept {
return N; }
194 template <
class C> constexpr
auto data(C& c) -> decltype(c.data()) {
return c.data(); }
196 template <
class C> constexpr
auto data(
const C& c) -> decltype(c.data()) {
return c.data(); }
198 template <
class T, std::
size_t N> constexpr T* data(T (&array)[N]) noexcept {
return array; }
200 template <
class E> constexpr
const E* data(std::initializer_list<E> il) noexcept {
return il.begin(); }
203 #if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_void_t)
206 template <
typename...>
using void_t = void;
209 template <
typename T>
using uncvref_t =
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
211 template <
typename>
struct is_span : std::false_type {};
213 template <
typename T, std::
size_t S>
struct is_span<
span<T, S>> : std::true_type {};
217 template <
typename T, std::
size_t N>
struct is_std_array<std::array<T, N>> : std::true_type {};
221 template <
typename T>
222 struct has_size_and_data<T, void_t<decltype(detail::size(std::declval<T>())), decltype(detail::data(std::declval<T>()))>> : std::true_type {
229 template <
typename T>
using remove_pointer_t =
typename std::remove_pointer<T>::type;
233 template <
typename T,
typename E>
236 typename std::enable_if<!std::is_same<typename std::remove_cv<decltype(detail::data(std::declval<T>()))>::type, void>::value &&
237 std::is_convertible<remove_pointer_t<decltype(detail::data(std::declval<T>()))> (*)[], E (*)[]>::value>::type>
240 template <
typename,
typename =
size_t>
struct is_complete : std::false_type {};
242 template <
typename T>
struct is_complete<T, decltype(sizeof(T))> : std::true_type {};
246 template <
typename ElementType, std::
size_t Extent>
class span {
247 static_assert(std::is_object<ElementType>::value,
"A span's ElementType must be an object type (not a "
248 "reference type or void)");
251 static_assert(!std::is_abstract<ElementType>::value,
"A span's ElementType cannot be an abstract class type");
257 using element_type = ElementType;
258 using value_type =
typename std::remove_cv<ElementType>::type;
259 using size_type = std::size_t;
260 using difference_type = std::ptrdiff_t;
261 using pointer = element_type*;
262 using const_pointer =
const element_type*;
263 using reference = element_type&;
264 using const_reference =
const element_type&;
265 using iterator = pointer;
266 using reverse_iterator = std::reverse_iterator<iterator>;
268 static constexpr size_type extent = Extent;
271 template <std::
size_t E = Extent,
typename std::enable_if<(E == dynamic_extent || E <= 0),
int>::type = 0> constexpr span() noexcept {}
273 TCB_SPAN_CONSTEXPR11 span(po
inter ptr,
size_type count)
274 : storage_(ptr, count) {
275 TCB_SPAN_EXPECT(extent == dynamic_extent || count == extent);
278 TCB_SPAN_CONSTEXPR11 span(po
inter first_elem, po
inter last_elem)
279 : storage_(first_elem, last_elem - first_elem) {
280 TCB_SPAN_EXPECT(extent == dynamic_extent || last_elem - first_elem == static_cast<std::ptrdiff_t>(extent));
283 template <std::
size_t N, std::
size_t E = Extent,
284 typename std::enable_if<(E == dynamic_extent || N == E) &&
285 detail::is_container_element_type_compatible<element_type (&)[N], ElementType>::value,
287 constexpr
span(element_type (&arr)[N]) noexcept
288 : storage_(arr, N) {}
290 template <
typename T, std::size_t N, std::size_t E = Extent,
291 typename std::enable_if<(E == dynamic_extent || N == E) &&
294 TCB_SPAN_ARRAY_CONSTEXPR
span(std::array<T, N>& arr) noexcept
295 : storage_(arr.data(), N) {}
297 template <
typename T, std::size_t N, std::size_t E = Extent,
298 typename std::enable_if<(E == dynamic_extent || N == E) &&
301 TCB_SPAN_ARRAY_CONSTEXPR
span(
const std::array<T, N>& arr) noexcept
302 : storage_(arr.data(), N) {}
304 template <
typename Container, std::size_t E = Extent,
305 typename std::enable_if<E == dynamic_extent && detail::is_container<Container>::value &&
308 constexpr
span(Container& cont)
309 : storage_(detail::data(cont), detail::size(cont)) {}
311 template <
typename Container, std::size_t E = Extent,
312 typename std::enable_if<E == dynamic_extent && detail::is_container<Container>::value &&
315 constexpr
span(
const Container& cont)
316 : storage_(detail::data(cont), detail::size(cont)) {}
318 constexpr
span(
const span& other) noexcept =
default;
320 template <
typename OtherElementType, std::size_t OtherExtent,
321 typename std::enable_if<(Extent == dynamic_extent || OtherExtent == dynamic_extent || Extent == OtherExtent) &&
322 std::is_convertible<OtherElementType (*)[], ElementType (*)[]>::value,
325 : storage_(other.data(), other.size()) {}
327 ~
span() noexcept =
default;
329 TCB_SPAN_CONSTEXPR_ASSIGN
span& operator=(
const span& other) noexcept =
default;
333 TCB_SPAN_EXPECT(Count <= size());
334 return {data(), Count};
338 TCB_SPAN_EXPECT(Count <= size());
339 return {data() + (size() - Count), Count};
342 template <std::
size_t Offset, std::
size_t Count = dynamic_extent>
344 span<ElementType, Count != dynamic_extent ? Count : (Extent != dynamic_extent ? Extent - Offset : dynamic_extent)>;
347 TCB_SPAN_EXPECT(Offset <= size() && (Count == dynamic_extent || Offset + Count <= size()));
348 return {data() + Offset, Count != dynamic_extent ? Count : size() - Offset};
352 TCB_SPAN_EXPECT(count <= size());
353 return {data(), count};
357 TCB_SPAN_EXPECT(count <= size());
358 return {data() + (size() - count), count};
362 TCB_SPAN_EXPECT(offset <= size() && (count == dynamic_extent || offset + count <= size()));
363 return {data() + offset, count == dynamic_extent ? size() - offset : count};
367 constexpr size_type size()
const noexcept {
return storage_.size; }
369 constexpr size_type size_bytes()
const noexcept {
return size() *
sizeof(element_type); }
371 TCB_SPAN_NODISCARD constexpr
bool empty()
const noexcept {
return size() == 0; }
374 TCB_SPAN_CONSTEXPR11 reference operator[](size_type idx)
const {
375 TCB_SPAN_EXPECT(idx < size());
376 return *(data() + idx);
379 TCB_SPAN_CONSTEXPR11 reference front()
const {
380 TCB_SPAN_EXPECT(!empty());
384 TCB_SPAN_CONSTEXPR11 reference back()
const {
385 TCB_SPAN_EXPECT(!empty());
386 return *(data() + (size() - 1));
389 constexpr pointer data()
const noexcept {
return storage_.ptr; }
392 constexpr iterator begin()
const noexcept {
return data(); }
394 constexpr iterator end()
const noexcept {
return data() + size(); }
396 TCB_SPAN_ARRAY_CONSTEXPR reverse_iterator rbegin()
const noexcept {
return reverse_iterator(end()); }
398 TCB_SPAN_ARRAY_CONSTEXPR reverse_iterator rend()
const noexcept {
return reverse_iterator(begin()); }
404 #ifdef TCB_SPAN_HAVE_DEDUCTION_GUIDES
409 template <
class T,
size_t N>
span(std::array<T, N>&) ->
span<T, N>;
413 template <
class Container>
424 template <
typename T, std::
size_t N> constexpr span<T, N> make_span(T (&arr)[N]) noexcept {
return {arr}; }
426 template <
typename T, std::
size_t N> TCB_SPAN_ARRAY_CONSTEXPR span<T, N> make_span(std::array<T, N>& arr) noexcept {
return {arr}; }
428 template <
typename T, std::
size_t N> TCB_SPAN_ARRAY_CONSTEXPR span<const T, N> make_span(
const std::array<T, N>& arr) noexcept {
432 template <
typename Container>
433 constexpr span<typename std::remove_reference<decltype(*detail::data(std::declval<Container&>()))>::type> make_span(Container& cont) {
437 template <
typename Container> constexpr span<const typename Container::value_type> make_span(
const Container& cont) {
return {cont}; }
439 template <
typename ElementType, std::
size_t Extent>
440 span<
const byte, ((Extent == dynamic_extent) ? dynamic_extent :
sizeof(ElementType) * Extent)>
441 as_bytes(span<ElementType, Extent> s) noexcept {
442 return {
reinterpret_cast<const byte*
>(s.data()), s.size_bytes()};
445 template <class ElementType, size_t Extent, typename std::enable_if<!std::is_const<ElementType>::value,
int>::type = 0>
446 span<byte, ((Extent == dynamic_extent) ? dynamic_extent :
sizeof(ElementType) * Extent)>
447 as_writable_bytes(span<ElementType, Extent> s) noexcept {
448 return {
reinterpret_cast<byte*
>(s.data()), s.size_bytes()};
451 template <std::
size_t N,
typename E, std::
size_t S> constexpr
auto get(span<E, S> s) -> decltype(s[N]) {
return s[N]; }
457 template <
typename ElementType,
size_t Extent>
458 class tuple_size<TCB_SPAN_NAMESPACE_NAME::span<ElementType, Extent>> :
public integral_constant<size_t, Extent> {};
460 template <
typename ElementType>
461 class tuple_size<TCB_SPAN_NAMESPACE_NAME::span<ElementType, TCB_SPAN_NAMESPACE_NAME::dynamic_extent>>;
463 template <size_t I, typename ElementType, size_t Extent> class tuple_element<I, TCB_SPAN_NAMESPACE_NAME::span<ElementType, Extent>> {
465 static_assert(Extent != TCB_SPAN_NAMESPACE_NAME::dynamic_extent && I < Extent,
"");
466 using type = ElementType;