General Utility Library for C++14  2.7
span.h
Go to the documentation of this file.
1 
20 #ifndef GUL14_SPAN_H_
21 #define GUL14_SPAN_H_
22 
23 #include <array>
24 #include <cstddef>
25 #include <cstdint>
26 #include <cstdio>
27 #include <stdexcept>
28 #include <type_traits>
29 
30 namespace gul14 {
31 
33 
34 // Feature test macro for defaulted constexpr assignment operator
35 #if (!defined(_MSC_VER) || _MSC_VER > 1900)
36 #define GUL_SPAN_CONSTEXPR_ASSIGN constexpr
37 #else
38 #define GUL_SPAN_CONSTEXPR_ASSIGN
39 #endif
40 
41 constexpr std::size_t dynamic_extent = SIZE_MAX;
42 
43 template <typename ElementType, std::size_t Extent = dynamic_extent>
44 class span;
45 
46 namespace detail {
47 
48 template <typename E, std::size_t S>
49 struct span_storage {
50  constexpr span_storage() noexcept = default;
51 
52  constexpr span_storage(E* pointer, std::size_t /*unused*/) noexcept : ptr(pointer)
53  {}
54 
55  E* ptr = nullptr;
56  static constexpr std::size_t size = S;
57 };
58 
59 template <typename E>
60 struct span_storage<E, dynamic_extent> {
61  constexpr span_storage() noexcept = default;
62 
63  constexpr span_storage(E* pointer, std::size_t sz) noexcept
64  : ptr(pointer), size(sz)
65  {}
66 
67  E* ptr = nullptr;
68  std::size_t size = 0;
69 };
70 
71 template <class C>
72 constexpr auto size(const C& c) -> decltype(c.size())
73 {
74  return c.size();
75 }
76 
77 template <class T, std::size_t N>
78 constexpr std::size_t size(const T (&)[N]) noexcept
79 {
80  return N;
81 }
82 
83 template <class C>
84 constexpr auto data(C& c) -> decltype(c.data())
85 {
86  return c.data();
87 }
88 
89 template <class C>
90 constexpr auto data(const C& c) -> decltype(c.data())
91 {
92  return c.data();
93 }
94 
95 template <class T, std::size_t N>
96 constexpr T* data(T (&array)[N]) noexcept
97 {
98  return array;
99 }
100 
101 template <class E>
102 constexpr const E* data(std::initializer_list<E> il) noexcept
103 {
104  return il.begin();
105 }
106 
107 template <typename...>
108 using void_t = void;
109 
110 template <typename T>
111 using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
112 
113 template <typename>
114 struct is_span : std::false_type {};
115 
116 template <typename T, std::size_t S>
117 struct is_span<span<T, S>> : std::true_type {};
118 
119 template <typename>
120 struct is_std_array : std::false_type {};
121 
122 template <typename T, std::size_t N>
123 struct is_std_array<std::array<T, N>> : std::true_type {};
124 
125 template <typename, typename = void>
126 struct has_size_and_data : std::false_type {};
127 
128 template <typename T>
129 struct has_size_and_data<T, void_t<decltype(detail::size(std::declval<T>())),
130  decltype(detail::data(std::declval<T>()))>>
131  : std::true_type {};
132 
133 template <typename C, typename U = uncvref_t<C>>
134 struct is_container {
135  static constexpr bool value =
136  !is_span<U>::value && !is_std_array<U>::value &&
137  !std::is_array<U>::value && has_size_and_data<C>::value;
138 };
139 
140 template <typename T>
141 using remove_pointer_t = typename std::remove_pointer<T>::type;
142 
143 template <typename, typename, typename = void>
144 struct is_container_element_type_compatible : std::false_type {};
145 
146 template <typename T, typename E>
147 struct is_container_element_type_compatible<
148  T, E, void_t<decltype(detail::data(std::declval<T>()))>>
149  : std::is_convertible<
150  remove_pointer_t<decltype(detail::data(std::declval<T>()))> (*)[],
151  E (*)[]> {};
152 
153 template <typename, typename = size_t>
154 struct is_complete : std::false_type {};
155 
156 template <typename T>
157 struct is_complete<T, decltype(sizeof(T))> : std::true_type {};
158 
159 } // namespace detail
160 
161 
163 
164 
171 template <typename ElementType, std::size_t Extent>
172 class span {
173  static_assert(std::is_object<ElementType>::value,
174  "A span's ElementType must be an object type (not a "
175  "reference type or void)");
176  static_assert(detail::is_complete<ElementType>::value,
177  "A span's ElementType must be a complete type (not a forward "
178  "declaration)");
179  static_assert(!std::is_abstract<ElementType>::value,
180  "A span's ElementType cannot be an abstract class type");
181 
182  using storage_type = detail::span_storage<ElementType, Extent>;
183 
184 public:
185  // constants and types
186  using element_type = ElementType;
187  using value_type = typename std::remove_cv<ElementType>::type;
188  using index_type = std::size_t;
189  using difference_type = std::ptrdiff_t;
191  using const_pointer = const element_type*;
193  using iterator = pointer;
195  using reverse_iterator = std::reverse_iterator<iterator>;
196  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
197 
199  static constexpr index_type extent = Extent;
200 
201  // [span.cons], span constructors, copy, assignment, and destructor
203  template <
204  std::size_t E = Extent,
205  typename std::enable_if<(E == dynamic_extent || E <= 0), int>::type = 0>
206  constexpr span() noexcept
207  {}
208 
210  constexpr span(pointer ptr, index_type count)
211  : storage_(ptr, count)
212  {}
213 
215  constexpr span(pointer first_elem, pointer last_elem)
216  : storage_(first_elem, last_elem - first_elem)
217  {}
218 
220  template <std::size_t N, std::size_t E = Extent,
221  typename std::enable_if<
222  (E == dynamic_extent || N == E) &&
223  detail::is_container_element_type_compatible<
224  element_type (&)[N], ElementType>::value,
225  int>::type = 0>
226  constexpr span(element_type (&arr)[N]) noexcept : storage_(arr, N)
227  {}
228 
230  template <std::size_t N, std::size_t E = Extent,
231  typename std::enable_if<
232  (E == dynamic_extent || N == E) &&
233  detail::is_container_element_type_compatible<
234  std::array<value_type, N>&, ElementType>::value,
235  int>::type = 0>
236  span(std::array<value_type, N>& arr) noexcept
237  : storage_(arr.data(), N)
238  {}
239 
241  template <std::size_t N, std::size_t E = Extent,
242  typename std::enable_if<
243  (E == dynamic_extent || N == E) &&
244  detail::is_container_element_type_compatible<
245  const std::array<value_type, N>&, ElementType>::value,
246  int>::type = 0>
247  span(const std::array<value_type, N>& arr) noexcept
248  : storage_(arr.data(), N)
249  {}
250 
252  template <
253  typename Container, std::size_t E = Extent,
254  typename std::enable_if<
255  E == dynamic_extent && detail::is_container<Container>::value &&
256  detail::is_container_element_type_compatible<
257  Container&, ElementType>::value,
258  int>::type = 0>
259  constexpr span(Container& cont)
260  : storage_(detail::data(cont), detail::size(cont))
261  {}
262 
264  template <
265  typename Container, std::size_t E = Extent,
266  typename std::enable_if<
267  E == dynamic_extent && detail::is_container<Container>::value &&
268  detail::is_container_element_type_compatible<
269  const Container&, ElementType>::value,
270  int>::type = 0>
271  constexpr span(const Container& cont)
272  : storage_(detail::data(cont), detail::size(cont))
273  {}
274 
276  constexpr span(const span& other) noexcept = default;
277 
279  template <typename OtherElementType, std::size_t OtherExtent,
280  typename std::enable_if<
281  (Extent == OtherExtent || Extent == dynamic_extent) &&
282  std::is_convertible<OtherElementType (*)[],
283  ElementType (*)[]>::value,
284  int>::type = 0>
285  constexpr span(const span<OtherElementType, OtherExtent>& other) noexcept
286  : storage_(other.data(), other.size())
287  {}
288 
290  ~span() noexcept = default;
291 
293  GUL_SPAN_CONSTEXPR_ASSIGN span&
294  operator=(const span& other) noexcept = default;
295 
296  // [span.sub], span subviews
298  template <std::size_t Count>
299  constexpr span<element_type, Count> first() const
300  {
301  return {data(), Count};
302  }
303 
305  template <std::size_t Count>
306  constexpr span<element_type, Count> last() const
307  {
308  return {data() + (size() - Count), Count};
309  }
310 
312  template <std::size_t Offset, std::size_t Count = dynamic_extent>
313  using subspan_return_t =
314  span<ElementType, Count != dynamic_extent
315  ? Count
316  : (Extent != dynamic_extent ? Extent - Offset
317  : dynamic_extent)>;
318 
320  template <std::size_t Offset, std::size_t Count = dynamic_extent>
322  {
323  return {data() + Offset,
324  Count != dynamic_extent ? Count : size() - Offset};
325  }
326 
329  first(index_type count) const
330  {
331  return {data(), count};
332  }
333 
336  last(index_type count) const
337  {
338  return {data() + (size() - count), count};
339  }
340 
343  subspan(index_type offset, index_type count = dynamic_extent) const
344  {
345  return {data() + offset,
346  count == dynamic_extent ? size() - offset : count};
347  }
348 
349  // [span.obs], span observers
351  constexpr index_type size() const noexcept { return storage_.size; }
352 
354  constexpr index_type size_bytes() const noexcept
355  {
356  return size() * sizeof(element_type);
357  }
358 
360  constexpr bool empty() const noexcept
361  {
362  return size() == 0;
363  }
364 
365  // [span.elem], span element access
367  constexpr reference operator[](index_type idx) const
368  {
369  return *(data() + idx);
370  }
371 
373  constexpr reference front() const
374  {
375  return *data();
376  }
377 
379  constexpr reference back() const
380  {
381  return *(data() + (size() - 1));
382  }
383 
385  constexpr pointer data() const noexcept { return storage_.ptr; }
386 
387  // [span.iterators], span iterator support
389  constexpr iterator begin() const noexcept { return data(); }
390 
392  constexpr iterator end() const noexcept { return data() + size(); }
393 
395  constexpr const_iterator cbegin() const noexcept { return begin(); }
396 
398  constexpr const_iterator cend() const noexcept { return end(); }
399 
401  reverse_iterator rbegin() const noexcept
402  {
403  return reverse_iterator(end());
404  }
405 
407  reverse_iterator rend() const noexcept
408  {
409  return reverse_iterator(begin());
410  }
411 
414  {
415  return const_reverse_iterator(cend());
416  }
417 
419  const_reverse_iterator crend() const noexcept
420  {
421  return const_reverse_iterator(cbegin());
422  }
423 
425  friend constexpr iterator begin(span s) noexcept { return s.begin(); }
426 
428  friend constexpr iterator end(span s) noexcept { return s.end(); }
429 
430 private:
431  storage_type storage_{};
432 };
433 
435 
436 /* Comparison operators */
437 // Implementation note: the implementations of == and < are equivalent to
438 // 4-legged std::equal and std::lexicographical_compare respectively
439 
440 template <typename T, std::size_t X, typename U, std::size_t Y>
441 constexpr bool operator==(span<T, X> lhs, span<U, Y> rhs)
442 {
443  if (lhs.size() != rhs.size()) {
444  return false;
445  }
446 
447  for (std::size_t i = 0; i < lhs.size(); i++) {
448  if (lhs[i] != rhs[i]) {
449  return false;
450  }
451  }
452 
453  return true;
454 }
455 
456 template <typename T, std::size_t X, typename U, std::size_t Y>
457 constexpr bool operator!=(span<T, X> lhs, span<U, Y> rhs)
458 {
459  return !(lhs == rhs);
460 }
461 
462 template <typename T, std::size_t X, typename U, std::size_t Y>
463 constexpr bool operator<(span<T, X> lhs, span<U, Y> rhs)
464 {
465  // No std::min to avoid dragging in <algorithm>
466  const std::size_t size = lhs.size() < rhs.size() ? lhs.size() : rhs.size();
467 
468  for (std::size_t i = 0; i < size; i++) {
469  if (lhs[i] < rhs[i]) {
470  return true;
471  }
472  if (lhs[i] > rhs[i]) {
473  return false;
474  }
475  }
476  return lhs.size() < rhs.size();
477 }
478 
479 template <typename T, std::size_t X, typename U, std::size_t Y>
480 constexpr bool operator<=(span<T, X> lhs, span<U, Y> rhs)
481 {
482  return !(rhs < lhs);
483 }
484 
485 template <typename T, std::size_t X, typename U, std::size_t Y>
486 constexpr bool operator>(span<T, X> lhs, span<U, Y> rhs)
487 {
488  return rhs < lhs;
489 }
490 
491 template <typename T, std::size_t X, typename U, std::size_t Y>
492 constexpr bool operator>=(span<T, X> lhs, span<U, Y> rhs)
493 {
494  return !(lhs < rhs);
495 }
496 
498 
507 template <typename ElementType, std::size_t Extent>
508 span<const unsigned char, ((Extent == dynamic_extent) ? dynamic_extent
509  : sizeof(ElementType) * Extent)>
511 {
512  return {reinterpret_cast<const unsigned char *>(s.data()), s.size_bytes()};
513 }
514 
523 template <
524  class ElementType, size_t Extent,
525  typename std::enable_if<!std::is_const<ElementType>::value, int>::type = 0>
526 span<unsigned char, ((Extent == dynamic_extent) ? dynamic_extent
527  : sizeof(ElementType) * Extent)>
529 {
530  return {reinterpret_cast<unsigned char *>(s.data()), s.size_bytes()};
531 }
532 
541 template <std::size_t N, typename E, std::size_t S>
542 constexpr auto get(span<E, S> s) -> decltype(s[N])
543 {
544  return s[N];
545 }
546 
547 } // namespace gul14
548 
549 
550 namespace std {
551 
552 template <typename ElementType, size_t Extent>
553 class tuple_size<gul14::span<ElementType, Extent>>
554  : public integral_constant<size_t, Extent> {};
555 
556 template <typename ElementType>
557 class tuple_size<gul14::span<ElementType, gul14::dynamic_extent>>; // not defined
558 
559 template <size_t I, typename ElementType, size_t Extent>
560 class tuple_element<I, gul14::span<ElementType, Extent>> {
561 public:
562  static_assert(Extent != gul14::dynamic_extent && I < Extent, "");
563  using type = ElementType;
564 };
565 
566 } // namespace std
567 
568 #endif
569 
570 // vi:ts=4:sw=4:sts=4:et
gul14::span::size_bytes
constexpr index_type size_bytes() const noexcept
See std::span.
Definition: span.h:354
gul14::span::pointer
element_type * pointer
See std::span.
Definition: span.h:190
gul14::get
constexpr auto get(span< E, S > s) -> decltype(s[N])
Return a reference to the Nth element of a given span.
Definition: span.h:542
gul14::span::span
constexpr span(pointer first_elem, pointer last_elem)
See std::span.
Definition: span.h:215
gul14::as_writable_bytes
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:528
gul14::span::span
constexpr span(element_type(&arr)[N]) noexcept
See std::span.
Definition: span.h:226
gul14::span::rend
reverse_iterator rend() const noexcept
See std::span.
Definition: span.h:407
gul14::span::span
constexpr span(const span< OtherElementType, OtherExtent > &other) noexcept
See std::span.
Definition: span.h:285
gul14::span::empty
constexpr bool empty() const noexcept
See std::span.
Definition: span.h:360
gul14::span::first
constexpr span< element_type, Count > first() const
See std::span.
Definition: span.h:299
gul14::span::front
constexpr reference front() const
See std::span.
Definition: span.h:373
gul14::span::back
constexpr reference back() const
See std::span.
Definition: span.h:379
gul14::span::const_reverse_iterator
std::reverse_iterator< const_iterator > const_reverse_iterator
See std::span.
Definition: span.h:196
gul14::span::const_iterator
const_pointer const_iterator
See std::span.
Definition: span.h:194
gul14::span::reference
element_type & reference
See std::span.
Definition: span.h:192
gul14::span::subspan
constexpr subspan_return_t< Offset, Count > subspan() const
See std::span.
Definition: span.h:321
gul14::span::span
constexpr span(Container &cont)
See std::span.
Definition: span.h:259
gul14::span::begin
constexpr iterator begin() const noexcept
See std::span.
Definition: span.h:389
gul14::span
A view to a contiguous sequence of objects.
Definition: span.h:172
gul14::span::rbegin
reverse_iterator rbegin() const noexcept
See std::span.
Definition: span.h:401
gul14::span::crbegin
const_reverse_iterator crbegin() const noexcept
See std::span.
Definition: span.h:413
gul14::span::value_type
typename std::remove_cv< ElementType >::type value_type
See std::span.
Definition: span.h:187
gul14::span::operator[]
constexpr reference operator[](index_type idx) const
See std::span.
Definition: span.h:367
gul14::span::end
constexpr iterator end() const noexcept
See std::span.
Definition: span.h:392
gul14::span::subspan
constexpr span< element_type, dynamic_extent > subspan(index_type offset, index_type count=dynamic_extent) const
See std::span.
Definition: span.h:343
gul14::span::span
constexpr span() noexcept
See std::span.
Definition: span.h:206
gul14::span::index_type
std::size_t index_type
See std::span.
Definition: span.h:188
gul14::span::difference_type
std::ptrdiff_t difference_type
See std::span.
Definition: span.h:189
gul14::span::cend
constexpr const_iterator cend() const noexcept
See std::span.
Definition: span.h:398
gul14::span::span
constexpr span(const Container &cont)
See std::span.
Definition: span.h:271
gul14::span::element_type
ElementType element_type
See std::span.
Definition: span.h:186
gul14::span::reverse_iterator
std::reverse_iterator< iterator > reverse_iterator
See std::span.
Definition: span.h:195
gul14::span::subspan_return_t
span< ElementType, Count !=dynamic_extent ? Count :(Extent !=dynamic_extent ? Extent - Offset :dynamic_extent)> subspan_return_t
See std::span.
Definition: span.h:317
gul14::span::span
constexpr span(pointer ptr, index_type count)
See std::span.
Definition: span.h:210
gul14::span::iterator
pointer iterator
See std::span.
Definition: span.h:193
gul14::span::span
span(const std::array< value_type, N > &arr) noexcept
See std::span.
Definition: span.h:247
gul14::span::last
constexpr span< element_type, dynamic_extent > last(index_type count) const
See std::span.
Definition: span.h:336
gul14::span::first
constexpr span< element_type, dynamic_extent > first(index_type count) const
See std::span.
Definition: span.h:329
gul14::span::last
constexpr span< element_type, Count > last() const
See std::span.
Definition: span.h:306
gul14::span::cbegin
constexpr const_iterator cbegin() const noexcept
See std::span.
Definition: span.h:395
gul14::span::extent
static constexpr index_type extent
See std::span.
Definition: span.h:199
gul14::span::const_pointer
const element_type * const_pointer
See std::span.
Definition: span.h:191
gul14
Namespace gul14 contains all functions and classes of the General Utility Library.
Definition: doxygen.h:26
gul14::span::begin
constexpr friend iterator begin(span s) noexcept
See std::span.
Definition: span.h:425
gul14::span::span
span(std::array< value_type, N > &arr) noexcept
See std::span.
Definition: span.h:236
gul14::as_bytes
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:510
gul14::span::~span
~span() noexcept=default
See std::span.
gul14::span::size
constexpr index_type size() const noexcept
See std::span.
Definition: span.h:351
gul14::span::data
constexpr pointer data() const noexcept
See std::span.
Definition: span.h:385
gul14::span::end
constexpr friend iterator end(span s) noexcept
See std::span.
Definition: span.h:428
gul14::span::crend
const_reverse_iterator crend() const noexcept
See std::span.
Definition: span.h:419