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