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