span.h
Go to the documentation of this file.
1 #ifndef TTG_UTIL_SPAN_H
2 #define TTG_UTIL_SPAN_H
3 
4 /* if TCB_SPAN_NAMESPACE_NAME already defined someone imported TCB span somewhere,
5  * then reset it here to the ttg namespace, don't forget to revert back */
6 #ifdef TCB_SPAN_NAMESPACE_NAME
7 
8 #define TTG_TCB_SPAN_NAMESPACE_NAME_AT_TOP_OF_SPAN_H TCB_SPAN_NAMESPACE_NAME
9 #undef TCB_SPAN_NAMESPACE_NAME
10 
11 #endif
12 
13 /* Use the TTG namespace */
14 #define TCB_SPAN_NAMESPACE_NAME ttg
15 
16 /*
17 This is an implementation of C++20's std::span
18 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/n4820.pdf
19 Code taken from https://github.com/tcbrindle/span/
20 */
21 
22 // Copyright Tristan Brindle 2018.
23 // Distributed under the Boost Software License, Version 1.0.
24 // (See accompanying file ../../LICENSE_1_0.txt or copy at
25 // https://www.boost.org/LICENSE_1_0.txt)
26 
27 #include <array>
28 #include <cstddef>
29 #include <cstdint>
30 #include <type_traits>
31 
32 #ifndef TCB_SPAN_NO_EXCEPTIONS
33 // Attempt to discover whether we're being compiled with exception support
34 #if !(defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND))
35 #define TCB_SPAN_NO_EXCEPTIONS
36 #endif
37 #endif
38 
39 #ifndef TCB_SPAN_NO_EXCEPTIONS
40 #include <cstdio>
41 #include <stdexcept>
42 #endif
43 
44 // Various feature test macros
45 
46 #ifndef TCB_SPAN_NAMESPACE_NAME
47 #define TCB_SPAN_NAMESPACE_NAME tcb
48 #endif
49 
50 #if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
51 #define TCB_SPAN_HAVE_CPP17
52 #endif
53 
54 #if __cplusplus >= 201402L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L)
55 #define TCB_SPAN_HAVE_CPP14
56 #endif
57 
59 
60 // Establish default contract checking behavior
61 #if !defined(TCB_SPAN_THROW_ON_CONTRACT_VIOLATION) && !defined(TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION) && \
62  !defined(TCB_SPAN_NO_CONTRACT_CHECKING)
63 #if defined(NDEBUG) || !defined(TCB_SPAN_HAVE_CPP14)
64 #define TCB_SPAN_NO_CONTRACT_CHECKING
65 #else
66 #define TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION
67 #endif
68 #endif
69 
70 #if defined(TCB_SPAN_THROW_ON_CONTRACT_VIOLATION)
71  struct contract_violation_error : std::logic_error {
72  explicit contract_violation_error(const char* msg) : std::logic_error(msg) {}
73  };
74 
75  inline void contract_violation(const char* msg) { throw contract_violation_error(msg); }
76 
77 #elif defined(TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION)
78  [[noreturn]] inline void contract_violation(const char* /*unused*/) { std::terminate(); }
79 #endif
80 
81 #if !defined(TCB_SPAN_NO_CONTRACT_CHECKING)
82 #define TCB_SPAN_STRINGIFY(cond) #cond
83 #define TCB_SPAN_EXPECT(cond) cond ? (void)0 : contract_violation("Expected " TCB_SPAN_STRINGIFY(cond))
84 #else
85 #define TCB_SPAN_EXPECT(cond)
86 #endif
87 
88 #if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_inline_variables)
89 #define TCB_SPAN_INLINE_VAR inline
90 #else
91 #define TCB_SPAN_INLINE_VAR
92 #endif
93 
94 #if defined(TCB_SPAN_HAVE_CPP14) || (defined(__cpp_constexpr) && __cpp_constexpr >= 201304)
95 #define TCB_SPAN_HAVE_CPP14_CONSTEXPR
96 #endif
97 
98 #if defined(TCB_SPAN_HAVE_CPP14_CONSTEXPR)
99 #define TCB_SPAN_CONSTEXPR14 constexpr
100 #else
101 #define TCB_SPAN_CONSTEXPR14
102 #endif
103 
104 #if defined(TCB_SPAN_HAVE_CPP14_CONSTEXPR) && (!defined(_MSC_VER) || _MSC_VER > 1900)
105 #define TCB_SPAN_CONSTEXPR_ASSIGN constexpr
106 #else
107 #define TCB_SPAN_CONSTEXPR_ASSIGN
108 #endif
109 
110 #if defined(TCB_SPAN_NO_CONTRACT_CHECKING)
111 #define TCB_SPAN_CONSTEXPR11 constexpr
112 #else
113 #define TCB_SPAN_CONSTEXPR11 TCB_SPAN_CONSTEXPR14
114 #endif
115 
116 #if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_deduction_guides)
117 #define TCB_SPAN_HAVE_DEDUCTION_GUIDES
118 #endif
119 
120 #if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_byte)
121 #define TCB_SPAN_HAVE_STD_BYTE
122 #endif
123 
124 #if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_array_constexpr)
125 #define TCB_SPAN_HAVE_CONSTEXPR_STD_ARRAY_ETC
126 #endif
127 
128 #if defined(TCB_SPAN_HAVE_CONSTEXPR_STD_ARRAY_ETC)
129 #define TCB_SPAN_ARRAY_CONSTEXPR constexpr
130 #else
131 #define TCB_SPAN_ARRAY_CONSTEXPR
132 #endif
133 
134 #ifdef TCB_SPAN_HAVE_STD_BYTE
135  using byte = std::byte;
136 #else
137  using byte = unsigned char;
138 #endif
139 
140 #if defined(TCB_SPAN_HAVE_CPP17)
141 #define TCB_SPAN_NODISCARD [[nodiscard]]
142 #else
143 #define TCB_SPAN_NODISCARD
144 #endif
145 
146  TCB_SPAN_INLINE_VAR constexpr std::size_t dynamic_extent = SIZE_MAX;
147 
148  template <typename ElementType, std::size_t Extent = dynamic_extent>
149  class span;
150 
151  namespace detail {
152 
153  template <typename E, std::size_t S>
154  struct span_storage {
155  constexpr span_storage() noexcept = default;
156 
157  constexpr span_storage(E* p_ptr, std::size_t /*unused*/) noexcept : ptr(p_ptr) {}
158 
159  E* ptr = nullptr;
160  static constexpr std::size_t size = S;
161  };
162 
163  template <typename E>
165  constexpr span_storage() noexcept = default;
166 
167  constexpr span_storage(E* p_ptr, std::size_t p_size) noexcept : ptr(p_ptr), size(p_size) {}
168 
169  E* ptr = nullptr;
170  std::size_t size = 0;
171  };
172 
173 // Reimplementation of C++17 std::size() and std::data()
174 #if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_nonmember_container_access)
175  using std::data;
176  using std::size;
177 #else
178  template <class C>
179  constexpr auto size(const C& c) -> decltype(c.size()) {
180  return c.size();
181  }
182 
183  template <class T, std::size_t N>
184  constexpr std::size_t size(const T (&)[N]) noexcept {
185  return N;
186  }
187 
188  template <class C>
189  constexpr auto data(C& c) -> decltype(c.data()) {
190  return c.data();
191  }
192 
193  template <class C>
194  constexpr auto data(const C& c) -> decltype(c.data()) {
195  return c.data();
196  }
197 
198  template <class T, std::size_t N>
199  constexpr T* data(T (&array)[N]) noexcept {
200  return array;
201  }
202 
203  template <class E>
204  constexpr const E* data(std::initializer_list<E> il) noexcept {
205  return il.begin();
206  }
207 #endif // TCB_SPAN_HAVE_CPP17
208 
209 #if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_void_t)
210  using std::void_t;
211 #else
212  template <typename...>
213  using void_t = void;
214 #endif
215 
216  template <typename T>
217  using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
218 
219  template <typename>
220  struct is_span : std::false_type {};
221 
222  template <typename T, std::size_t S>
223  struct is_span<span<T, S> > : std::true_type {};
224 
225  template <typename>
226  struct is_std_array : std::false_type {};
227 
228  template <typename T, std::size_t N>
229  struct is_std_array<std::array<T, N> > : std::true_type {};
230 
231  template <typename, typename = void>
232  struct has_size_and_data : std::false_type {};
233 
234  template <typename T>
236  T, void_t<decltype(detail::size(std::declval<T>())), decltype(detail::data(std::declval<T>()))> >
237  : std::true_type {};
238 
239  template <typename C, typename U = uncvref_t<C> >
240  struct is_container {
241  static constexpr bool value =
242  !is_span<U>::value && !is_std_array<U>::value && !std::is_array<U>::value && has_size_and_data<C>::value;
243  };
244 
245  template <typename T>
246  using remove_pointer_t = typename std::remove_pointer<T>::type;
247 
248  template <typename, typename, typename = void>
249  struct is_container_element_type_compatible : std::false_type {};
250 
251  template <typename T, typename E>
253  T, E,
254  typename std::enable_if<
255  !std::is_same<typename std::remove_cv<decltype(detail::data(std::declval<T>()))>::type, void>::value>::type>
256  : std::is_convertible<remove_pointer_t<decltype(detail::data(std::declval<T>()))> (*)[], E (*)[]> {};
257 
258  template <typename, typename = size_t>
259  struct is_complete : std::false_type {};
260 
261  template <typename T>
262  struct is_complete<T, decltype(sizeof(T))> : std::true_type {};
263 
264  } // namespace detail
265 
266  template <typename ElementType, std::size_t Extent>
267  class span {
268  static_assert(std::is_object<ElementType>::value,
269  "A span's ElementType must be an object type (not a "
270  "reference type or void)");
272  "A span's ElementType must be a complete type (not a forward "
273  "declaration)");
274  static_assert(!std::is_abstract<ElementType>::value, "A span's ElementType cannot be an abstract class type");
275 
277 
278  public:
279  // constants and types
280  using element_type = ElementType;
281  using value_type = typename std::remove_cv<ElementType>::type;
282  using size_type = std::size_t;
283  using difference_type = std::ptrdiff_t;
285  using const_pointer = const element_type*;
288  using iterator = pointer;
289  using reverse_iterator = std::reverse_iterator<iterator>;
290 
291  static constexpr size_type extent = Extent;
292 
293  // [span.cons], span constructors, copy, assignment, and destructor
294  template <std::size_t E = Extent, typename std::enable_if<(E == dynamic_extent || E <= 0), int>::type = 0>
295  constexpr span() noexcept {}
296 
297  TCB_SPAN_CONSTEXPR11 span(pointer ptr, size_type count) : storage_(ptr, count) {
298  TCB_SPAN_EXPECT(extent == dynamic_extent || count == extent);
299  }
300 
301  TCB_SPAN_CONSTEXPR11 span(pointer first_elem, pointer last_elem) : storage_(first_elem, last_elem - first_elem) {
302  TCB_SPAN_EXPECT(extent == dynamic_extent || last_elem - first_elem == static_cast<std::ptrdiff_t>(extent));
303  }
304 
305  template <std::size_t N, std::size_t E = Extent,
306  typename std::enable_if<(E == dynamic_extent || N == E) && detail::is_container_element_type_compatible<
307  element_type (&)[N], ElementType>::value,
308  int>::type = 0>
309  constexpr span(element_type (&arr)[N]) noexcept : storage_(arr, N) {}
310 
311  template <std::size_t N, std::size_t E = Extent,
312  typename std::enable_if<
313  (E == dynamic_extent || N == E) &&
314  detail::is_container_element_type_compatible<std::array<value_type, N>&, ElementType>::value,
315  int>::type = 0>
316  TCB_SPAN_ARRAY_CONSTEXPR span(std::array<value_type, N>& arr) noexcept : storage_(arr.data(), N) {}
317 
318  template <std::size_t N, std::size_t E = Extent,
319  typename std::enable_if<(E == dynamic_extent || N == E) &&
320  detail::is_container_element_type_compatible<const std::array<value_type, N>&,
321  ElementType>::value,
322  int>::type = 0>
323  TCB_SPAN_ARRAY_CONSTEXPR span(const std::array<value_type, N>& arr) noexcept : storage_(arr.data(), N) {}
324 
325  template <typename Container, std::size_t E = Extent,
326  typename std::enable_if<E == dynamic_extent && detail::is_container<Container>::value &&
328  int>::type = 0>
329  constexpr span(Container& cont) : storage_(detail::data(cont), detail::size(cont)) {}
330 
331  template <
332  typename Container, std::size_t E = Extent,
333  typename std::enable_if<E == dynamic_extent && detail::is_container<Container>::value &&
335  int>::type = 0>
336  constexpr span(const Container& cont) : storage_(detail::data(cont), detail::size(cont)) {}
337 
338  constexpr span(const span& other) noexcept = default;
339 
340  template <typename OtherElementType, std::size_t OtherExtent,
341  typename std::enable_if<(Extent == OtherExtent || Extent == dynamic_extent) &&
342  std::is_convertible<OtherElementType (*)[], ElementType (*)[]>::value,
343  int>::type = 0>
344  constexpr span(const span<OtherElementType, OtherExtent>& other) noexcept : storage_(other.data(), other.size()) {}
345 
346  ~span() noexcept = default;
347 
348  TCB_SPAN_CONSTEXPR_ASSIGN span& operator=(const span& other) noexcept = default;
349 
350  // [span.sub], span subviews
351  template <std::size_t Count>
353  TCB_SPAN_EXPECT(Count <= size());
354  return {data(), Count};
355  }
356 
357  template <std::size_t Count>
359  TCB_SPAN_EXPECT(Count <= size());
360  return {data() + (size() - Count), Count};
361  }
362 
363  template <std::size_t Offset, std::size_t Count = dynamic_extent>
365  span<ElementType,
366  Count != dynamic_extent ? Count : (Extent != dynamic_extent ? Extent - Offset : dynamic_extent)>;
367 
368  template <std::size_t Offset, std::size_t Count = dynamic_extent>
370  TCB_SPAN_EXPECT(Offset <= size() && (Count == dynamic_extent || Offset + Count <= size()));
371  return {data() + Offset, Count != dynamic_extent ? Count : size() - Offset};
372  }
373 
375  TCB_SPAN_EXPECT(count <= size());
376  return {data(), count};
377  }
378 
380  TCB_SPAN_EXPECT(count <= size());
381  return {data() + (size() - count), count};
382  }
383 
385  size_type count = dynamic_extent) const {
386  TCB_SPAN_EXPECT(offset <= size() && (count == dynamic_extent || offset + count <= size()));
387  return {data() + offset, count == dynamic_extent ? size() - offset : count};
388  }
389 
390  // [span.obs], span observers
391  constexpr size_type size() const noexcept { return storage_.size; }
392 
393  constexpr size_type size_bytes() const noexcept { return size() * sizeof(element_type); }
394 
395  TCB_SPAN_NODISCARD constexpr bool empty() const noexcept { return size() == 0; }
396 
397  // [span.elem], span element access
399  TCB_SPAN_EXPECT(idx < size());
400  return *(data() + idx);
401  }
402 
405  return *data();
406  }
407 
410  return *(data() + (size() - 1));
411  }
412 
413  constexpr pointer data() const noexcept { return storage_.ptr; }
414 
415  // [span.iterators], span iterator support
416  constexpr iterator begin() const noexcept { return data(); }
417 
418  constexpr iterator end() const noexcept { return data() + size(); }
419 
421 
423 
424  private:
425  storage_type storage_{};
426  };
427 
428 #ifdef TCB_SPAN_HAVE_DEDUCTION_GUIDES
429 
430  /* Deduction Guides */
431  template <class T, size_t N>
432  span(T (&)[N]) -> span<T, N>;
433 
434  template <class T, size_t N>
435  span(std::array<T, N>&) -> span<T, N>;
436 
437  template <class T, size_t N>
438  span(const std::array<T, N>&) -> span<const T, N>;
439 
440  template <class Container>
441  span(Container&) -> span<typename Container::value_type>;
442 
443  template <class Container>
444  span(const Container&) -> span<const typename Container::value_type>;
445 
446 #endif // TCB_HAVE_DEDUCTION_GUIDES
447 
448  template <typename ElementType, std::size_t Extent>
450  return s;
451  }
452 
453  template <typename T, std::size_t N>
454  constexpr span<T, N> make_span(T (&arr)[N]) noexcept {
455  return {arr};
456  }
457 
458  template <typename T, std::size_t N>
459  TCB_SPAN_ARRAY_CONSTEXPR span<T, N> make_span(std::array<T, N>& arr) noexcept {
460  return {arr};
461  }
462 
463  template <typename T, std::size_t N>
464  TCB_SPAN_ARRAY_CONSTEXPR span<const T, N> make_span(const std::array<T, N>& arr) noexcept {
465  return {arr};
466  }
467 
468  template <typename Container>
469  constexpr span<typename Container::value_type> make_span(Container& cont) {
470  return {cont};
471  }
472 
473  template <typename Container>
474  constexpr span<const typename Container::value_type> make_span(const Container& cont) {
475  return {cont};
476  }
477 
478  template <typename ElementType, std::size_t Extent>
479  span<const byte, ((Extent == dynamic_extent) ? dynamic_extent : sizeof(ElementType) * Extent)> as_bytes(
480  span<ElementType, Extent> s) noexcept {
481  return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
482  }
483 
484  template <class ElementType, size_t Extent,
485  typename std::enable_if<!std::is_const<ElementType>::value, int>::type = 0>
486  span<byte, ((Extent == dynamic_extent) ? dynamic_extent : sizeof(ElementType) * Extent)> as_writable_bytes(
487  span<ElementType, Extent> s) noexcept {
488  return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
489  }
490 
491  template <std::size_t N, typename E, std::size_t S>
492  constexpr auto get(span<E, S> s) -> decltype(s[N]) {
493  return s[N];
494  }
495 
496 } // namespace TCB_SPAN_NAMESPACE_NAME
497 
498 namespace std {
499 
500  template <typename ElementType, size_t Extent>
501  class tuple_size<TCB_SPAN_NAMESPACE_NAME::span<ElementType, Extent> > : public integral_constant<size_t, Extent> {};
502 
503  template <typename ElementType>
504  class tuple_size<TCB_SPAN_NAMESPACE_NAME::span<ElementType, TCB_SPAN_NAMESPACE_NAME::dynamic_extent> >; // not
505  // defined
506 
507  template <size_t I, typename ElementType, size_t Extent>
508  class tuple_element<I, TCB_SPAN_NAMESPACE_NAME::span<ElementType, Extent> > {
509  public:
510  static_assert(Extent != TCB_SPAN_NAMESPACE_NAME::dynamic_extent && I < Extent, "");
511  using type = ElementType;
512  };
513 
514 } // end namespace std
515 
516 /* revert TCB_SPAN_NAMESPACE_NAME to the original value, if needed */
517 #ifdef TTG_TCB_SPAN_NAMESPACE_NAME_AT_TOP_OF_SPAN_H
518 
519 #undef TCB_SPAN_NAMESPACE_NAME
520 #define TCB_SPAN_NAMESPACE_NAME TTG_TCB_SPAN_NAMESPACE_NAME_AT_TOP_OF_SPAN_H
521 #undef TTG_TCB_SPAN_NAMESPACE_NAME_AT_TOP_OF_SPAN_H
522 
523 #endif
524 
525 #endif // TTG_UTIL_SPAN_H
constexpr span(Container &cont)
Definition: span.h:329
TCB_SPAN_CONSTEXPR11 span< element_type, Count > last() const
Definition: span.h:358
TCB_SPAN_CONSTEXPR11 subspan_return_t< Offset, Count > subspan() const
Definition: span.h:369
constexpr TCB_SPAN_NODISCARD bool empty() const noexcept
Definition: span.h:395
TCB_SPAN_ARRAY_CONSTEXPR span(const std::array< value_type, N > &arr) noexcept
Definition: span.h:323
constexpr iterator end() const noexcept
Definition: span.h:418
~span() noexcept=default
constexpr span(const Container &cont)
Definition: span.h:336
std::reverse_iterator< iterator > reverse_iterator
Definition: span.h:289
ElementType element_type
Definition: span.h:280
constexpr iterator begin() const noexcept
Definition: span.h:416
TCB_SPAN_ARRAY_CONSTEXPR span(std::array< value_type, N > &arr) noexcept
Definition: span.h:316
static constexpr size_type extent
Definition: span.h:291
const element_type * const_pointer
Definition: span.h:285
constexpr span(const span &other) noexcept=default
TCB_SPAN_CONSTEXPR11 span< element_type, dynamic_extent > first(size_type count) const
Definition: span.h:374
typename std::remove_cv< ElementType >::type value_type
Definition: span.h:281
TCB_SPAN_ARRAY_CONSTEXPR reverse_iterator rbegin() const noexcept
Definition: span.h:420
const element_type & const_reference
Definition: span.h:287
std::ptrdiff_t difference_type
Definition: span.h:283
TCB_SPAN_CONSTEXPR11 span< element_type, Count > first() const
Definition: span.h:352
TCB_SPAN_CONSTEXPR11 span< element_type, dynamic_extent > last(size_type count) const
Definition: span.h:379
TCB_SPAN_CONSTEXPR11 reference back() const
Definition: span.h:408
constexpr size_type size() const noexcept
Definition: span.h:391
TCB_SPAN_CONSTEXPR11 reference front() const
Definition: span.h:403
constexpr size_type size_bytes() const noexcept
Definition: span.h:393
TCB_SPAN_CONSTEXPR11 reference operator[](size_type idx) const
Definition: span.h:398
constexpr span(element_type(&arr)[N]) noexcept
Definition: span.h:309
constexpr pointer data() const noexcept
Definition: span.h:413
TCB_SPAN_ARRAY_CONSTEXPR reverse_iterator rend() const noexcept
Definition: span.h:422
constexpr span(const span< OtherElementType, OtherExtent > &other) noexcept
Definition: span.h:344
element_type * pointer
Definition: span.h:284
TCB_SPAN_CONSTEXPR11 span< element_type, dynamic_extent > subspan(size_type offset, size_type count=dynamic_extent) const
Definition: span.h:384
element_type & reference
Definition: span.h:286
typename std::remove_cv< typename std::remove_reference< T >::type >::type uncvref_t
Definition: span.h:217
constexpr std::size_t size(const T(&)[N]) noexcept
Definition: span.h:184
constexpr auto size(const C &c) -> decltype(c.size())
Definition: span.h:179
typename std::remove_pointer< T >::type remove_pointer_t
Definition: span.h:246
constexpr const E * data(std::initializer_list< E > il) noexcept
Definition: span.h:204
constexpr auto data(C &c) -> decltype(c.data())
Definition: span.h:189
span< byte,((Extent==dynamic_extent) ? dynamic_extent :sizeof(ElementType) *Extent)> as_writable_bytes(span< ElementType, Extent > s) noexcept
Definition: span.h:486
constexpr span< ElementType, Extent > make_span(span< ElementType, Extent > s) noexcept
Definition: span.h:449
constexpr auto get(span< E, S > s) -> decltype(s[N])
Definition: span.h:492
span< const byte,((Extent==dynamic_extent) ? dynamic_extent :sizeof(ElementType) *Extent)> as_bytes(span< ElementType, Extent > s) noexcept
Definition: span.h:479
constexpr TCB_SPAN_INLINE_VAR std::size_t dynamic_extent
Definition: span.h:146
unsigned char byte
Definition: span.h:137
#define TCB_SPAN_EXPECT(cond)
Definition: span.h:85
#define TCB_SPAN_INLINE_VAR
Definition: span.h:91
#define TCB_SPAN_NODISCARD
Definition: span.h:143
#define TCB_SPAN_ARRAY_CONSTEXPR
Definition: span.h:131
#define TCB_SPAN_CONSTEXPR_ASSIGN
Definition: span.h:107
#define TCB_SPAN_CONSTEXPR11
Definition: span.h:111
constexpr span_storage() noexcept=default
static constexpr std::size_t size
Definition: span.h:160