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