Vc  1.3.3-dev
SIMD Vector Classes for C++
span.h
1 // -*- C++ -*-
2 //===------------------------------ span ---------------------------------===//
3 //
4 // The LLVM Compiler Infrastructure
5 //
6 // This file is dual licensed under the MIT and the University of Illinois Open
7 // Source Licenses. See LICENSE.TXT for details.
8 //
9 // Adapted for use with Vc:
10 // Copyright © 2018 Matthias Kretz <kretz@kde.org>
11 //===---------------------------------------------------------------------===//
12 
13 #ifndef VC_COMMON_SPAN_H_
14 #define VC_COMMON_SPAN_H_
15 
16 #include <array> // for array
17 #include <cstddef> // for ptrdiff_t
18 #include <cstddef> // for std::byte
19 #include <iterator> // for iterators
20 #include <type_traits> // for remove_cv, etc
21 #include "subscript.h" // for AdaptSubscriptOperator
22 
23 namespace Vc_VERSIONED_NAMESPACE
24 {
25 #ifdef __cpp_inline_variables
26 inline
27 #endif
28  constexpr ptrdiff_t dynamic_extent = -1;
29 namespace Common
30 {
31 template <typename T, ptrdiff_t Extent = dynamic_extent> class span;
32 
33 template <typename T, ptrdiff_t Extent>
34 constexpr auto begin(const span<T, Extent>& s) noexcept -> decltype(s.begin())
35 {
36  return s.begin();
37 }
38 template <typename T, ptrdiff_t Extent>
39 constexpr auto end(const span<T, Extent>& s) noexcept -> decltype(s.end())
40 {
41  return s.end();
42 }
43 
44 template <class T> struct _is_span_impl : public std::false_type {
45 };
46 
47 template <class T, ptrdiff_t Extent>
48 struct _is_span_impl<span<T, Extent>> : public std::true_type {
49 };
50 
51 template <class T>
52 struct _is_span : public _is_span_impl<typename std::remove_cv<T>::type> {
53 };
54 
55 template <class T> struct _is_std_array_impl : public std::false_type {
56 };
57 
58 template <class T, size_t Sz>
59 struct _is_std_array_impl<array<T, Sz>> : public std::true_type {
60 };
61 
62 template <class T>
63 struct _is_std_array : public _is_std_array_impl<typename std::remove_cv<T>::type> {
64 };
65 
66 template <class T, class ElementType, class = void>
67 struct _is_span_compatible_container : public std::false_type {
68 };
69 
70 template <class... Ts> using _void_t = void;
71 
72 template <class C> constexpr auto _std_data(C& c) -> decltype(c.data())
73 {
74  return c.data();
75 }
76 template <class C> constexpr auto _std_data(const C& c) -> decltype(c.data())
77 {
78  return c.data();
79 }
80 template <class T, std::size_t N> constexpr T* _std_data(T (&array)[N]) noexcept
81 {
82  return array;
83 }
84 template <class E> constexpr const E* _std_data(std::initializer_list<E> il) noexcept
85 {
86  return il.begin();
87 }
88 
89 template <class C> constexpr auto _std_size(const C& c) -> decltype(c.size())
90 {
91  return c.size();
92 }
93 template <class T, std::size_t N>
94 constexpr std::size_t _std_size(const T (&array)[N]) noexcept
95 {
96  return N;
97 }
98 
99 template <class T, class ElementType>
100 struct _is_span_compatible_container<
101  T, ElementType,
102  _void_t<
103  // is not a specialization of span
104  typename std::enable_if<!_is_span<T>::value, std::nullptr_t>::type,
105  // is not a specialization of array
106  typename std::enable_if<!_is_std_array<T>::value, std::nullptr_t>::type,
107  // is_array_v<Container> is false,
108  typename std::enable_if<!std::is_array<T>::value, std::nullptr_t>::type,
109  // data(cont) and size(cont) are well formed
110  decltype(data(std::declval<T>())), decltype(size(std::declval<T>())),
111  // remove_pointer_t<decltype(data(cont))>(*)[] is convertible to ElementType(*)[]
112  typename std::enable_if<
113  std::is_convertible<typename std::remove_pointer<decltype(
114  data(std::declval<T&>()))>::type (*)[],
115  ElementType (*)[]>::value,
116  std::nullptr_t>::type>> : public std::true_type {
117 };
118 
119 #if defined Vc_MSVC || (defined Vc_GCC && Vc_GCC < 0x50100)
120 #define Vc_CONSTEXPR
121 #else
122 #define Vc_CONSTEXPR constexpr
123 #endif
124 
125 template <typename T, ptrdiff_t Extent> class span
126 {
127 public:
128  // constants and types
129  using element_type = T;
130  using value_type = typename std::remove_cv<T>::type;
131  using index_type = ptrdiff_t;
132  using difference_type = ptrdiff_t;
133  using pointer = T*;
134  using const_pointer = const T*; // not in standard
135  using reference = T&;
136  using const_reference = const T&; // not in standard
137  using iterator = pointer;
138  using const_iterator = const_pointer;
139  using reverse_iterator = std::reverse_iterator<iterator>;
140  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
141 
142  static constexpr index_type extent = Extent;
143  static_assert(Extent >= 0, "Can't have a span with an extent < 0");
144 
145  // [span.cons], span constructors, copy, assignment, and destructor
146  Vc_CONSTEXPR span() noexcept : data_{nullptr}
147  {
148  static_assert(Extent == 0,
149  "Can't default construct a statically sized span with size > 0");
150  }
151 
152  Vc_CONSTEXPR span(const span&) noexcept = default;
153  Vc_CONSTEXPR span& operator=(const span&) noexcept = default;
154 
155  Vc_CONSTEXPR span(pointer _ptr, index_type _count) : data_{_ptr}
156  {
157  (void)_count;
158  Vc_ASSERT(("size mismatch in span's constructor (ptr, len)", Extent == _count));
159  }
160  Vc_CONSTEXPR span(pointer _f, pointer _l) : data_{_f}
161  {
162  (void)_l;
163  Vc_ASSERT(("size mismatch in span's constructor (ptr, ptr)",
164  Extent == distance(_f, _l)));
165  }
166 
167  Vc_CONSTEXPR span(element_type (&_arr)[Extent]) noexcept : data_{_arr} {}
168  Vc_CONSTEXPR span(array<value_type, Extent>& _arr) noexcept : data_{_arr.data()} {}
169  Vc_CONSTEXPR span(const array<value_type, Extent>& _arr) noexcept : data_{_arr.data()} {}
170 
171  template <class Container>
172  inline Vc_CONSTEXPR span(
173  Container& _c,
174  typename std::enable_if<_is_span_compatible_container<Container, T>::value,
175  std::nullptr_t>::type = nullptr)
176  : data_{_std_data(_c)}
177  {
178  Vc_ASSERT(("size mismatch in span's constructor (container))",
179  Extent == _std_size(_c)));
180  }
181 
182  template <class Container>
183  inline Vc_CONSTEXPR span(
184  const Container& _c,
185  typename std::enable_if<_is_span_compatible_container<const Container, T>::value,
186  std::nullptr_t>::type = nullptr)
187  : data_{_std_data(_c)}
188  {
189  Vc_ASSERT(("size mismatch in span's constructor (const container)",
190  Extent == _std_size(_c)));
191  }
192 
193  template <class OtherElementType>
194  inline Vc_CONSTEXPR span(
195  const span<OtherElementType, Extent>& _other,
196  typename std::enable_if<
197  std::is_convertible<OtherElementType (*)[], element_type (*)[]>::value,
198  std::nullptr_t>::type = nullptr)
199  : data_{_other.data()}
200  {
201  }
202 
203  template <class OtherElementType>
204  inline Vc_CONSTEXPR span(
205  const span<OtherElementType, dynamic_extent>& _other,
206  typename std::enable_if<
207  std::is_convertible<OtherElementType (*)[], element_type (*)[]>::value,
208  std::nullptr_t>::type = nullptr) noexcept
209  : data_{_other.data()}
210  {
211  Vc_ASSERT(("size mismatch in span's constructor (other span)",
212  Extent == _other.size()));
213  }
214 
215  // ~span() noexcept = default;
216 
217  template <ptrdiff_t Count>
218  inline Vc_CONSTEXPR span<element_type, Count> first() const noexcept
219  {
220  static_assert(Count >= 0, "Count must be >= 0 in span::first()");
221  static_assert(Count <= Extent, "Count out of range in span::first()");
222  return {data(), Count};
223  }
224 
225  template <ptrdiff_t Count>
226  inline Vc_CONSTEXPR span<element_type, Count> last() const noexcept
227  {
228  static_assert(Count >= 0, "Count must be >= 0 in span::last()");
229  static_assert(Count <= Extent, "Count out of range in span::last()");
230  return {data() + size() - Count, Count};
231  }
232 
233  Vc_CONSTEXPR span<element_type, dynamic_extent> first(index_type _count) const noexcept
234  {
235  Vc_ASSERT(("Count out of range in span::first(count)",
236  _count >= 0 && _count <= size()));
237  return {data(), _count};
238  }
239 
240  Vc_CONSTEXPR span<element_type, dynamic_extent> last(index_type _count) const noexcept
241  {
242  Vc_ASSERT(
243  ("Count out of range in span::last(count)", _count >= 0 && _count <= size()));
244  return {data() + size() - _count, _count};
245  }
246 
247 #ifndef Vc_MSVC
248  // MSVC 190024215 fails with "error C2059: syntax error: '<end Parse>'" somewhere in
249  // this file. Unless someone needs this function on MSVC, I don't see a reason to
250  // invest time into working around their bugs.
251  template <ptrdiff_t Offset, ptrdiff_t Count = dynamic_extent>
252  inline Vc_CONSTEXPR auto subspan() const noexcept
253  -> span<element_type, Count != dynamic_extent ? Count : Extent - Offset>
254  {
255  Vc_ASSERT(
256  ("Offset out of range in span::subspan()", Offset >= 0 && Offset <= size()));
257  return {data() + Offset, Count == dynamic_extent ? size() - Offset : Count};
258  }
259 
260  inline Vc_CONSTEXPR span<element_type, dynamic_extent> subspan(
261  index_type offset, index_type count = dynamic_extent) const noexcept
262  {
263  Vc_ASSERT(("Offset out of range in span::subspan(offset, count)",
264  offset >= 0 && offset <= size()));
265  Vc_ASSERT(("Count out of range in span::subspan(offset, count)",
266  (count >= 0 && count <= size()) || count == dynamic_extent));
267  if (count == dynamic_extent) {
268  return {data() + offset, size() - offset};
269  }
270  Vc_ASSERT(("count + offset out of range in span::subspan(offset, count)",
271  offset + count <= size()));
272  return {data() + offset, count};
273  }
274 #endif // Vc_MSVC
275 
276  Vc_CONSTEXPR index_type size() const noexcept { return Extent; }
277  Vc_CONSTEXPR index_type size_bytes() const noexcept
278  {
279  return Extent * sizeof(element_type);
280  }
281  Vc_CONSTEXPR bool empty() const noexcept { return Extent == 0; }
282 
283  Vc_CONSTEXPR reference operator[](index_type _idx) const noexcept
284  {
285  Vc_ASSERT(("span<T,N>[] index out of bounds", _idx >= 0 && _idx < size()));
286  return data_[_idx];
287  }
288 
289  Vc_CONSTEXPR reference operator()(index_type _idx) const noexcept
290  {
291  Vc_ASSERT(("span<T,N>() index out of bounds", _idx >= 0 && _idx < size()));
292  return data_[_idx];
293  }
294 
295  Vc_CONSTEXPR pointer data() const noexcept { return data_; }
296 
297  // [span.iter], span iterator support
298  Vc_CONSTEXPR iterator begin() const noexcept { return iterator(data()); }
299  Vc_CONSTEXPR iterator end() const noexcept { return iterator(data() + size()); }
300  Vc_CONSTEXPR const_iterator cbegin() const noexcept { return const_iterator(data()); }
301  Vc_CONSTEXPR const_iterator cend() const noexcept
302  {
303  return const_iterator(data() + size());
304  }
305  Vc_CONSTEXPR reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); }
306  Vc_CONSTEXPR reverse_iterator rend() const noexcept { return reverse_iterator(begin()); }
307  Vc_CONSTEXPR const_reverse_iterator crbegin() const noexcept
308  {
309  return const_reverse_iterator(cend());
310  }
311  Vc_CONSTEXPR const_reverse_iterator crend() const noexcept
312  {
313  return const_reverse_iterator(cbegin());
314  }
315 
316  Vc_CONSTEXPR void swap(span& _other) noexcept
317  {
318  pointer _p = data_;
319  data_ = _other.data_;
320  _other.data_ = _p;
321  }
322 
323 #ifdef __cpp_lib_byte
324  span<const std::byte, Extent * sizeof(element_type)> _as_bytes() const noexcept
325  {
326  return {reinterpret_cast<const std::byte*>(data()), size_bytes()};
327  }
328 
329  span<std::byte, Extent * sizeof(element_type)> _as_writeable_bytes() const noexcept
330  {
331  return {reinterpret_cast<std::byte*>(data()), size_bytes()};
332  }
333 #endif // __cpp_lib_byte
334 
335 private:
336  pointer data_;
337 };
338 
339 template <typename T> class span<T, dynamic_extent>
340 {
341 private:
342 public:
343  // constants and types
344  using element_type = T;
345  using value_type = typename std::remove_cv<T>::type;
346  using index_type = ptrdiff_t;
347  using difference_type = ptrdiff_t;
348  using pointer = T*;
349  using const_pointer = const T*; // not in standard
350  using reference = T&;
351  using const_reference = const T&; // not in standard
352  using iterator = pointer;
353  using const_iterator = const_pointer;
354  using reverse_iterator = std::reverse_iterator<iterator>;
355  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
356 
357  static constexpr index_type extent = dynamic_extent;
358 
359  // [span.cons], span constructors, copy, assignment, and destructor
360  Vc_CONSTEXPR span() noexcept : data_{nullptr}, size_{0} {}
361 
362  Vc_CONSTEXPR span(const span&) noexcept = default;
363  Vc_CONSTEXPR span& operator=(const span&) noexcept = default;
364 
365  Vc_CONSTEXPR span(pointer _ptr, index_type _count) : data_{_ptr}, size_{_count} {}
366  Vc_CONSTEXPR span(pointer _f, pointer _l) : data_{_f}, size_{distance(_f, _l)} {}
367 
368  template <size_t Sz>
369  inline Vc_CONSTEXPR span(element_type (&_arr)[Sz]) noexcept : data_{_arr}, size_{Sz}
370  {
371  }
372 
373  template <size_t Sz>
374  inline Vc_CONSTEXPR span(array<value_type, Sz>& _arr) noexcept
375  : data_{_arr.data()}, size_{Sz}
376  {
377  }
378 
379  template <size_t Sz>
380  inline Vc_CONSTEXPR span(const array<value_type, Sz>& _arr) noexcept
381  : data_{_arr.data()}, size_{Sz}
382  {
383  }
384 
385  template <class Container>
386  inline Vc_CONSTEXPR span(
387  Container& _c,
388  typename std::enable_if<_is_span_compatible_container<Container, T>::value,
389  std::nullptr_t>::type = nullptr)
390  : data_{_std_data(_c)}, size_{index_type(_std_size(_c))}
391  {
392  }
393 
394  template <class Container>
395  inline Vc_CONSTEXPR span(
396  const Container& _c,
397  typename std::enable_if<_is_span_compatible_container<const Container, T>::value,
398  std::nullptr_t>::type = nullptr)
399  : data_{_std_data(_c)}, size_{index_type(_std_size(_c))}
400  {
401  }
402 
403  template <class OtherElementType, ptrdiff_t OtherExtent>
404  inline Vc_CONSTEXPR span(
405  const span<OtherElementType, OtherExtent>& _other,
406  typename std::enable_if<
407  std::is_convertible<OtherElementType (*)[], element_type (*)[]>::value,
408  std::nullptr_t>::type = nullptr) noexcept
409  : data_{_other.data()}, size_{_other.size()}
410  {
411  }
412 
413  // ~span() noexcept = default;
414 
415  template <ptrdiff_t Count>
416  inline Vc_CONSTEXPR span<element_type, Count> first() const noexcept
417  {
418  static_assert(Count >= 0, "");
419  Vc_ASSERT(("Count out of range in span::first()", Count <= size()));
420  return {data(), Count};
421  }
422 
423  template <ptrdiff_t Count>
424  inline Vc_CONSTEXPR span<element_type, Count> last() const noexcept
425  {
426  static_assert(Count >= 0, "");
427  Vc_ASSERT(("Count out of range in span::last()", Count <= size()));
428  return {data() + size() - Count, Count};
429  }
430 
431  Vc_CONSTEXPR span<element_type, dynamic_extent> first(index_type _count) const noexcept
432  {
433  Vc_ASSERT(("Count out of range in span::first(count)",
434  _count >= 0 && _count <= size()));
435  return {data(), _count};
436  }
437 
438  Vc_CONSTEXPR span<element_type, dynamic_extent> last(index_type _count) const noexcept
439  {
440  Vc_ASSERT(
441  ("Count out of range in span::last(count)", _count >= 0 && _count <= size()));
442  return {data() + size() - _count, _count};
443  }
444 
445  template <ptrdiff_t Offset, ptrdiff_t Count = dynamic_extent>
446  inline Vc_CONSTEXPR span<T, dynamic_extent> subspan() const noexcept
447  {
448  Vc_ASSERT(
449  ("Offset out of range in span::subspan()", Offset >= 0 && Offset <= size()));
450  Vc_ASSERT(("Count out of range in span::subspan()",
451  Count == dynamic_extent || Offset + Count <= size()));
452  return {data() + Offset, Count == dynamic_extent ? size() - Offset : Count};
453  }
454 
455  Vc_CONSTEXPR span<element_type, dynamic_extent> inline subspan(
456  index_type _offset, index_type _count = dynamic_extent) const noexcept
457  {
458  Vc_ASSERT(("Offset out of range in span::subspan(offset, count)",
459  _offset >= 0 && _offset <= size()));
460  Vc_ASSERT(("count out of range in span::subspan(offset, count)",
461  (_count >= 0 && _count <= size()) || _count == dynamic_extent));
462  if (_count == dynamic_extent)
463  return {data() + _offset, size() - _offset};
464  Vc_ASSERT(("Offset + count out of range in span::subspan(offset, count)",
465  _offset + _count <= size()));
466  return {data() + _offset, _count};
467  }
468 
469  Vc_CONSTEXPR index_type size() const noexcept { return size_; }
470  Vc_CONSTEXPR index_type size_bytes() const noexcept
471  {
472  return size_ * sizeof(element_type);
473  }
474  Vc_CONSTEXPR bool empty() const noexcept { return size_ == 0; }
475 
476  Vc_CONSTEXPR reference operator[](index_type _idx) const noexcept
477  {
478  Vc_ASSERT(("span<T>[] index out of bounds", _idx >= 0 && _idx < size()));
479  return data_[_idx];
480  }
481 
482  Vc_CONSTEXPR reference operator()(index_type _idx) const noexcept
483  {
484  Vc_ASSERT(("span<T>() index out of bounds", _idx >= 0 && _idx < size()));
485  return data_[_idx];
486  }
487 
488  Vc_CONSTEXPR pointer data() const noexcept { return data_; }
489 
490  // [span.iter], span iterator support
491  Vc_CONSTEXPR iterator begin() const noexcept { return iterator(data()); }
492  Vc_CONSTEXPR iterator end() const noexcept { return iterator(data() + size()); }
493  Vc_CONSTEXPR const_iterator cbegin() const noexcept { return const_iterator(data()); }
494  Vc_CONSTEXPR const_iterator cend() const noexcept
495  {
496  return const_iterator(data() + size());
497  }
498  Vc_CONSTEXPR reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); }
499  Vc_CONSTEXPR reverse_iterator rend() const noexcept { return reverse_iterator(begin()); }
500  Vc_CONSTEXPR const_reverse_iterator crbegin() const noexcept
501  {
502  return const_reverse_iterator(cend());
503  }
504  Vc_CONSTEXPR const_reverse_iterator crend() const noexcept
505  {
506  return const_reverse_iterator(cbegin());
507  }
508 
509  Vc_CONSTEXPR void swap(span& _other) noexcept
510  {
511  pointer _p = data_;
512  data_ = _other.data_;
513  _other.data_ = _p;
514 
515  index_type _sz = size_;
516  size_ = _other.size_;
517  _other.size_ = _sz;
518  }
519 
520 #ifdef __cpp_lib_byte
521  span<const std::byte, dynamic_extent> _as_bytes() const noexcept
522  {
523  return {reinterpret_cast<const std::byte*>(data()), size_bytes()};
524  }
525 
526  span<std::byte, dynamic_extent> _as_writeable_bytes() const noexcept
527  {
528  return {reinterpret_cast<std::byte*>(data()), size_bytes()};
529  }
530 #endif // __cpp_lib_byte
531 
532 private:
533  pointer data_;
534  index_type size_;
535 };
536 
537 template <class T1, ptrdiff_t Extent1, class T2, ptrdiff_t Extent2>
538 Vc_CONSTEXPR bool operator==(const span<T1, Extent1>& lhs, const span<T2, Extent2>& rhs)
539 {
540  return equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
541 }
542 
543 template <class T1, ptrdiff_t Extent1, class T2, ptrdiff_t Extent2>
544 Vc_CONSTEXPR bool operator!=(const span<T1, Extent1>& lhs, const span<T2, Extent2>& rhs)
545 {
546  return !(rhs == lhs);
547 }
548 
549 template <class T1, ptrdiff_t Extent1, class T2, ptrdiff_t Extent2>
550 Vc_CONSTEXPR bool operator<(const span<T1, Extent1>& lhs, const span<T2, Extent2>& rhs)
551 {
552  return lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
553 }
554 
555 template <class T1, ptrdiff_t Extent1, class T2, ptrdiff_t Extent2>
556 Vc_CONSTEXPR bool operator<=(const span<T1, Extent1>& lhs, const span<T2, Extent2>& rhs)
557 {
558  return !(rhs < lhs);
559 }
560 
561 template <class T1, ptrdiff_t Extent1, class T2, ptrdiff_t Extent2>
562 Vc_CONSTEXPR bool operator>(const span<T1, Extent1>& lhs, const span<T2, Extent2>& rhs)
563 {
564  return rhs < lhs;
565 }
566 
567 template <class T1, ptrdiff_t Extent1, class T2, ptrdiff_t Extent2>
568 Vc_CONSTEXPR bool operator>=(const span<T1, Extent1>& lhs, const span<T2, Extent2>& rhs)
569 {
570  return !(lhs < rhs);
571 }
572 
573 // as_bytes & as_writeable_bytes
574 template <class T, ptrdiff_t Extent>
575 auto as_bytes(span<T, Extent> _s) noexcept -> decltype(_s._as_bytes())
576 {
577  return _s._as_bytes();
578 }
579 
580 template <class T, ptrdiff_t Extent>
581 auto as_writeable_bytes(span<T, Extent> _s) noexcept ->
582  typename std::enable_if<!std::is_const<T>::value,
583  decltype(_s._as_writeable_bytes())>::type
584 {
585  return _s._as_writeable_bytes();
586 }
587 
588 template <class T, ptrdiff_t Extent>
589 Vc_CONSTEXPR void swap(span<T, Extent>& lhs, span<T, Extent>& rhs) noexcept
590 {
591  lhs.swap(rhs);
592 }
593 
594 #undef Vc_CONSTEXPR
595 
596 // Deduction guides
597 #ifdef __cpp_deduction_guides
598 template <class T, size_t Sz> span(T (&)[Sz])->span<T, Sz>;
599 
600 template <class T, size_t Sz> span(array<T, Sz>&)->span<T, Sz>;
601 
602 template <class T, size_t Sz> span(const array<T, Sz>&)->span<const T, Sz>;
603 
604 template <class Container> span(Container&)->span<typename Container::value_type>;
605 
606 template <class Container>
607 span(const Container&)->span<const typename Container::value_type>;
608 #endif // __cpp_deduction_guides
609 
610 } // namespace Common
611 
634 template <typename T, ptrdiff_t Extent>
635 using span = Common::AdaptSubscriptOperator<Common::span<T, Extent>>;
636 
637 namespace Traits
638 {
639 template <typename T, ptrdiff_t Extent>
640 struct has_contiguous_storage_impl<Vc::span<T, Extent>> : public std::true_type {
641 };
642 template <typename T, ptrdiff_t Extent>
643 struct has_contiguous_storage_impl<Vc::Common::span<T, Extent>> : public std::true_type {
644 };
645 } // namespace Traits
646 
647 } // namespace Vc_VERSIONED_NAMESPACE
648 
649 #endif // VC_COMMON_SPAN_H_
void swap(Adapter< S, T, N > &a, std::size_t i, S &x)
Swaps one scalar object x with a SIMD slot at offset i in the simdized object a.
Definition: simdize.h:1105
Common::AdaptSubscriptOperator< Common::span< T, Extent >> span
An adapted std::span with additional subscript operators supporting gather and scatter operations...
Definition: span.h:635
Definition: vector.h:257
result_vector_type< L, R >::mask_type operator!=(L &&lhs, R &&rhs)
Applies != component-wise and concurrently.
Definition: simdarray.h:1642
result_vector_type< L, R >::mask_type operator==(L &&lhs, R &&rhs)
Applies == component-wise and concurrently.
Definition: simdarray.h:1642
result_vector_type< L, R >::mask_type operator>=(L &&lhs, R &&rhs)
Applies >= component-wise and concurrently.
Definition: simdarray.h:1642
result_vector_type< L, R >::mask_type operator>(L &&lhs, R &&rhs)
Applies > component-wise and concurrently.
Definition: simdarray.h:1642