General Utility Library for C++17 25.4.1
span.h
Go to the documentation of this file.
1
20#ifndef GUL17_SPAN_H_
21#define GUL17_SPAN_H_
22
23#include <array>
24#include <cstddef>
25#include <cstdint>
26#include <cstdio>
27#include <stdexcept>
28#include <type_traits>
29
30#include "gul17/traits.h"
31
32namespace gul17 {
33
41
42constexpr std::size_t dynamic_extent = SIZE_MAX;
43
44template <typename ElementType, std::size_t Extent = dynamic_extent>
45class span;
46
47namespace detail {
48
49template <typename E, std::size_t S>
50struct span_storage {
51 constexpr span_storage() noexcept = default;
52
53 constexpr span_storage(E* pointer, std::size_t /*unused*/) noexcept : ptr(pointer)
54 {}
55
56 E* ptr = nullptr;
57 static constexpr std::size_t size = S;
58};
59
60template <typename E>
62 constexpr span_storage() noexcept = default;
63
64 constexpr span_storage(E* pointer, std::size_t sz) noexcept
65 : ptr(pointer), size(sz)
66 {}
67
68 E* ptr = nullptr;
69 std::size_t size = 0;
70};
71
72template <class C>
73constexpr auto size(const C& c) -> decltype(c.size())
74{
75 return c.size();
76}
77
78template <class T, std::size_t N>
79constexpr std::size_t size(const T (&)[N]) noexcept
80{
81 return N;
82}
83
84template <class C>
85constexpr auto data(C& c) -> decltype(c.data())
86{
87 return c.data();
88}
89
90template <class C>
91constexpr auto data(const C& c) -> decltype(c.data())
92{
93 return c.data();
94}
95
96template <class T, std::size_t N>
97constexpr T* data(T (&array)[N]) noexcept
98{
99 return array;
100}
101
102template <class E>
103constexpr const E* data(std::initializer_list<E> il) noexcept
104{
105 return il.begin();
106}
107
108template <typename>
109struct is_span : std::false_type {};
110
111template <typename T, std::size_t S>
112struct is_span<span<T, S>> : std::true_type {};
113
114template <typename>
115struct is_std_array : std::false_type {};
116
117template <typename T, std::size_t N>
118struct is_std_array<std::array<T, N>> : std::true_type {};
119
120template <typename, typename = void>
121struct has_size_and_data : std::false_type {};
122
123template <typename T>
124struct has_size_and_data<T, std::void_t<decltype(detail::size(std::declval<T>())),
125 decltype(detail::data(std::declval<T>()))>>
126 : std::true_type {};
127
128template <typename C, typename U = remove_cvref_t<C>>
129struct is_container {
130 static constexpr bool value =
131 !is_span<U>::value && !is_std_array<U>::value &&
132 !std::is_array<U>::value && has_size_and_data<C>::value;
133};
134
135template <typename T>
136using remove_pointer_t = typename std::remove_pointer<T>::type;
137
138template <typename, typename, typename = void>
139struct is_container_element_type_compatible : std::false_type {};
140
141template <typename T, typename E>
143 T, E, std::void_t<decltype(detail::data(std::declval<T>()))>>
144 : std::is_convertible<
145 remove_pointer_t<decltype(detail::data(std::declval<T>()))> (*)[],
146 E (*)[]> {};
147
148template <typename, typename = size_t>
149struct is_complete : std::false_type {};
150
151template <typename T>
152struct is_complete<T, decltype(sizeof(T))> : std::true_type {};
153
154} // namespace detail
155
156
158
159
166template <typename ElementType, std::size_t Extent>
167class span {
168 static_assert(std::is_object<ElementType>::value,
169 "A span's ElementType must be an object type (not a "
170 "reference type or void)");
171 static_assert(detail::is_complete<ElementType>::value,
172 "A span's ElementType must be a complete type (not a forward "
173 "declaration)");
174 static_assert(!std::is_abstract<ElementType>::value,
175 "A span's ElementType cannot be an abstract class type");
176
177 using storage_type = detail::span_storage<ElementType, Extent>;
178
179public:
180 // constants and types
182 using value_type = typename std::remove_cv<ElementType>::type;
183 using index_type = std::size_t;
184 using difference_type = std::ptrdiff_t;
190 using reverse_iterator = std::reverse_iterator<iterator>;
191 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
192
194 static constexpr index_type extent = Extent;
195
196 // [span.cons], span constructors, copy, assignment, and destructor
198 template <
199 std::size_t E = Extent,
200 typename std::enable_if<(E == dynamic_extent || E <= 0), int>::type = 0>
201 constexpr span() noexcept
202 {}
203
206 : storage_(ptr, count)
207 {}
208
211 : storage_(first_elem, last_elem - first_elem)
212 {}
213
215 template <std::size_t N, std::size_t E = Extent,
216 typename std::enable_if<
217 (E == dynamic_extent || N == E) &&
218 detail::is_container_element_type_compatible<
220 int>::type = 0>
221 constexpr span(element_type (&arr)[N]) noexcept : storage_(arr, N)
222 {}
223
225 template <std::size_t N, std::size_t E = Extent,
226 typename std::enable_if<
227 (E == dynamic_extent || N == E) &&
228 detail::is_container_element_type_compatible<
229 std::array<value_type, N>&, ElementType>::value,
230 int>::type = 0>
231 span(std::array<value_type, N>& arr) noexcept
232 : storage_(arr.data(), N)
233 {}
234
236 template <std::size_t N, std::size_t E = Extent,
237 typename std::enable_if<
238 (E == dynamic_extent || N == E) &&
239 detail::is_container_element_type_compatible<
240 const std::array<value_type, N>&, ElementType>::value,
241 int>::type = 0>
242 span(const std::array<value_type, N>& arr) noexcept
243 : storage_(arr.data(), N)
244 {}
245
247 template <
248 typename Container, std::size_t E = Extent,
249 typename std::enable_if<
250 E == dynamic_extent && detail::is_container<Container>::value &&
251 detail::is_container_element_type_compatible<
253 int>::type = 0>
254 constexpr span(Container& cont)
255 : storage_(detail::data(cont), detail::size(cont))
256 {}
257
259 template <
260 typename Container, std::size_t E = Extent,
261 typename std::enable_if<
262 E == dynamic_extent && detail::is_container<Container>::value &&
263 detail::is_container_element_type_compatible<
265 int>::type = 0>
266 constexpr span(const Container& cont)
267 : storage_(detail::data(cont), detail::size(cont))
268 {}
269
271 constexpr span(const span& other) noexcept = default;
272
274 template <typename OtherElementType, std::size_t OtherExtent,
275 typename std::enable_if<
277 std::is_convertible<OtherElementType (*)[],
278 ElementType (*)[]>::value,
279 int>::type = 0>
281 : storage_(other.data(), other.size())
282 {}
283
286
290
291 // [span.sub], span subviews
293 template <std::size_t Count>
295 {
296 return {data(), Count};
297 }
298
300 template <std::size_t Count>
302 {
303 return {data() + (size() - Count), Count};
304 }
305
307 template <std::size_t Offset, std::size_t Count = dynamic_extent>
310 ? Count
312 : dynamic_extent)>;
313
315 template <std::size_t Offset, std::size_t Count = dynamic_extent>
317 {
318 return {data() + Offset,
320 }
321
325 {
326 return {data(), count};
327 }
328
332 {
333 return {data() + (size() - count), count};
334 }
335
339 {
340 return {data() + offset,
342 }
343
344 // [span.obs], span observers
346 constexpr index_type size() const noexcept { return storage_.size; }
347
350 {
351 return size() * sizeof(element_type);
352 }
353
355 constexpr bool empty() const noexcept
356 {
357 return size() == 0;
358 }
359
360 // [span.elem], span element access
363 {
364 return *(data() + idx);
365 }
366
368 constexpr reference front() const
369 {
370 return *data();
371 }
372
374 constexpr reference back() const
375 {
376 return *(data() + (size() - 1));
377 }
378
380 constexpr pointer data() const noexcept { return storage_.ptr; }
381
382 // [span.iterators], span iterator support
384 constexpr iterator begin() const noexcept { return data(); }
385
387 constexpr iterator end() const noexcept { return data() + size(); }
388
390 constexpr const_iterator cbegin() const noexcept { return begin(); }
391
393 constexpr const_iterator cend() const noexcept { return end(); }
394
400
406
412
418
420 friend constexpr iterator begin(span s) noexcept { return s.begin(); }
421
423 friend constexpr iterator end(span s) noexcept { return s.end(); }
424
425private:
426 storage_type storage_{};
427};
428
430
431/* Comparison operators */
432// Implementation note: the implementations of == and < are equivalent to
433// 4-legged std::equal and std::lexicographical_compare respectively
434
435template <typename T, std::size_t X, typename U, std::size_t Y>
436constexpr bool operator==(span<T, X> lhs, span<U, Y> rhs)
437{
438 if (lhs.size() != rhs.size()) {
439 return false;
440 }
441
442 for (std::size_t i = 0; i < lhs.size(); i++) {
443 if (lhs[i] != rhs[i]) {
444 return false;
445 }
446 }
447
448 return true;
449}
450
451template <typename T, std::size_t X, typename U, std::size_t Y>
452constexpr bool operator!=(span<T, X> lhs, span<U, Y> rhs)
453{
454 return !(lhs == rhs);
455}
456
457template <typename T, std::size_t X, typename U, std::size_t Y>
458constexpr bool operator<(span<T, X> lhs, span<U, Y> rhs)
459{
460 // No std::min to avoid dragging in <algorithm>
461 const std::size_t size = lhs.size() < rhs.size() ? lhs.size() : rhs.size();
462
463 for (std::size_t i = 0; i < size; i++) {
464 if (lhs[i] < rhs[i]) {
465 return true;
466 }
467 if (lhs[i] > rhs[i]) {
468 return false;
469 }
470 }
471 return lhs.size() < rhs.size();
472}
473
474template <typename T, std::size_t X, typename U, std::size_t Y>
475constexpr bool operator<=(span<T, X> lhs, span<U, Y> rhs)
476{
477 return !(rhs < lhs);
478}
479
480template <typename T, std::size_t X, typename U, std::size_t Y>
481constexpr bool operator>(span<T, X> lhs, span<U, Y> rhs)
482{
483 return rhs < lhs;
484}
485
486template <typename T, std::size_t X, typename U, std::size_t Y>
487constexpr bool operator>=(span<T, X> lhs, span<U, Y> rhs)
488{
489 return !(lhs < rhs);
490}
491
493
502template <typename ElementType, std::size_t Extent>
503span<const unsigned char, ((Extent == dynamic_extent) ? dynamic_extent
506{
507 return {reinterpret_cast<const unsigned char *>(s.data()), s.size_bytes()};
508}
509
518template <
519 class ElementType, size_t Extent,
520 typename std::enable_if<!std::is_const<ElementType>::value, int>::type = 0>
521span<unsigned char, ((Extent == dynamic_extent) ? dynamic_extent
524{
525 return {reinterpret_cast<unsigned char *>(s.data()), s.size_bytes()};
526}
527
536template <std::size_t N, typename E, std::size_t S>
537constexpr auto get(span<E, S> s) -> decltype(s[N])
538{
539 return s[N];
540}
541
543
544} // namespace gul17
545
546
547namespace std {
548
549template <typename ElementType, size_t Extent>
550class tuple_size<gul17::span<ElementType, Extent>>
551 : public integral_constant<size_t, Extent> {};
552
553template <typename ElementType>
554class tuple_size<gul17::span<ElementType, gul17::dynamic_extent>>; // not defined
555
556template <size_t I, typename ElementType, size_t Extent>
557class tuple_element<I, gul17::span<ElementType, Extent>> {
558public:
559 static_assert(Extent != gul17::dynamic_extent && I < Extent, "");
560 using type = ElementType;
561};
562
563} // namespace std
564
565#endif
566
567// vi:ts=4:sw=4:sts=4:et
A view to a contiguous sequence of objects.
Definition span.h:167
constexpr reference front() const
See std::span.
Definition span.h:368
constexpr span(pointer first_elem, pointer last_elem)
See std::span.
Definition span.h:210
static constexpr index_type extent
See std::span.
Definition span.h:194
const_reverse_iterator crend() const noexcept
See std::span.
Definition span.h:414
const_reverse_iterator crbegin() const noexcept
See std::span.
Definition span.h:408
constexpr span(const span< OtherElementType, OtherExtent > &other) noexcept
See std::span.
Definition span.h:280
constexpr iterator begin() const noexcept
See std::span.
Definition span.h:384
constexpr span() noexcept
See std::span.
Definition span.h:201
constexpr span< element_type, dynamic_extent > first(index_type count) const
See std::span.
Definition span.h:324
constexpr span(const span &other) noexcept=default
See std::span.
constexpr pointer data() const noexcept
See std::span.
Definition span.h:380
constexpr span(element_type(&arr)[N]) noexcept
See std::span.
Definition span.h:221
reverse_iterator rbegin() const noexcept
See std::span.
Definition span.h:396
constexpr const_iterator cend() const noexcept
See std::span.
Definition span.h:393
reverse_iterator rend() const noexcept
See std::span.
Definition span.h:402
std::reverse_iterator< iterator > reverse_iterator
See std::span.
Definition span.h:190
pointer iterator
See std::span.
Definition span.h:188
constexpr subspan_return_t< Offset, Count > subspan() const
See std::span.
Definition span.h:316
constexpr index_type size() const noexcept
See std::span.
Definition span.h:346
constexpr index_type size_bytes() const noexcept
See std::span.
Definition span.h:349
friend constexpr iterator end(span s) noexcept
See std::span.
Definition span.h:423
std::reverse_iterator< const_iterator > const_reverse_iterator
See std::span.
Definition span.h:191
const element_type * const_pointer
See std::span.
Definition span.h:186
std::size_t index_type
See std::span.
Definition span.h:183
constexpr span(const Container &cont)
See std::span.
Definition span.h:266
ElementType element_type
See std::span.
Definition span.h:181
constexpr span< element_type, Count > first() const
See std::span.
Definition span.h:294
const_pointer const_iterator
See std::span.
Definition span.h:189
constexpr span(Container &cont)
See std::span.
Definition span.h:254
constexpr reference operator[](index_type idx) const
See std::span.
Definition span.h:362
friend constexpr iterator begin(span s) noexcept
See std::span.
Definition span.h:420
constexpr const_iterator cbegin() const noexcept
See std::span.
Definition span.h:390
element_type & reference
See std::span.
Definition span.h:187
typename std::remove_cv< ElementType >::type value_type
See std::span.
Definition span.h:182
std::ptrdiff_t difference_type
See std::span.
Definition span.h:184
constexpr iterator end() const noexcept
See std::span.
Definition span.h:387
constexpr span< element_type, dynamic_extent > subspan(index_type offset, index_type count=dynamic_extent) const
See std::span.
Definition span.h:338
~span() noexcept=default
See std::span.
constexpr span(pointer ptr, index_type count)
See std::span.
Definition span.h:205
element_type * pointer
See std::span.
Definition span.h:185
span(const std::array< value_type, N > &arr) noexcept
See std::span.
Definition span.h:242
span(std::array< value_type, N > &arr) noexcept
See std::span.
Definition span.h:231
constexpr span< element_type, Count > last() const
See std::span.
Definition span.h:301
constexpr reference back() const
See std::span.
Definition span.h:374
constexpr bool empty() const noexcept
See std::span.
Definition span.h:355
constexpr span< element_type, dynamic_extent > last(index_type count) const
See std::span.
Definition span.h:331
auto constexpr bit_set(unsigned bit) noexcept -> ReturnT
Set a bit in an integral type.
Definition bit_manip.h:121
span< unsigned char,((Extent==dynamic_extent) ? dynamic_extent :sizeof(ElementType) *Extent)> as_writable_bytes(span< ElementType, Extent > s) noexcept
Return a writable view to the byte representation of the elements of a given span.
Definition span.h:523
span< const unsigned char,((Extent==dynamic_extent) ? dynamic_extent :sizeof(ElementType) *Extent)> as_bytes(span< ElementType, Extent > s) noexcept
Return a constant view to the byte representation of the elements of a given span.
Definition span.h:505
constexpr auto get(span< E, S > s) -> decltype(s[N])
Return a reference to the Nth element of a given span.
Definition span.h:537
Namespace gul17 contains all functions and classes of the General Utility Library.
Definition doxygen.h:26
Some metaprogramming traits for the General Utility Library.