28 #ifndef VC_COMMON_MEMORYBASE_H_ 29 #define VC_COMMON_MEMORYBASE_H_ 32 #include <type_traits> 36 namespace Vc_VERSIONED_NAMESPACE
41 #define Vc_MEM_OPERATOR_EQ(op) \ 42 template<typename T> \ 43 Vc_ALWAYS_INLINE enable_if_mutable<T, MemoryVector &> operator op##=(const T &x) { \ 44 const V v = value() op x; \ 45 v.store(&m_data[0], Flags()); \ 57 template<
typename _V,
typename Flags>
class MemoryVector
59 typedef typename std::remove_cv<_V>::type V;
61 template<
typename T,
typename R>
using enable_if_mutable =
62 typename std::enable_if<std::is_same<T, T>::value && !std::is_const<_V>::value, R>::type;
65 typename std::conditional<std::is_const<_V>::value,
const typename V::EntryType,
66 typename V::EntryType>::type;
67 typedef typename V::Mask Mask;
69 EntryType m_data[V::Size];
74 Vc_INTRINSIC MemoryVector() =
default;
78 MemoryVector(
const MemoryVector &) =
delete;
79 MemoryVector(MemoryVector &&) =
delete;
84 Vc_ALWAYS_INLINE Vc_PURE V value()
const {
return V(&m_data[0], Flags()); }
91 Vc_ALWAYS_INLINE Vc_PURE
operator V()
const {
return value(); }
94 Vc_ALWAYS_INLINE enable_if_mutable<T, MemoryVector &> operator=(
const T &x) {
97 v.store(&m_data[0], Flags());
101 Vc_ALL_BINARY(Vc_MEM_OPERATOR_EQ);
102 Vc_ALL_ARITHMETICS(Vc_MEM_OPERATOR_EQ);
104 Vc_ALWAYS_INLINE EntryType &operator[](
size_t i) {
return m_data[i]; }
105 Vc_ALWAYS_INLINE
const EntryType &operator[](
size_t i)
const {
return m_data[i]; }
108 template<
typename _V,
typename Flags>
class MemoryVectorIterator
110 typedef typename std::remove_cv<_V>::type V;
112 template<
typename T,
typename R>
using enable_if_mutable =
113 typename std::enable_if<std::is_same<T, T>::value && !std::is_const<_V>::value, R>::type;
115 using iterator_traits = std::iterator_traits<MemoryVector<_V, Flags> *>;
119 typedef typename iterator_traits::difference_type difference_type;
120 typedef typename iterator_traits::value_type value_type;
121 typedef typename iterator_traits::pointer pointer;
122 typedef typename iterator_traits::reference reference;
123 typedef typename iterator_traits::iterator_category iterator_category;
126 constexpr MemoryVectorIterator(
const MemoryVectorIterator &) =
default;
127 constexpr MemoryVectorIterator(MemoryVectorIterator &&) =
default;
128 Vc_ALWAYS_INLINE MemoryVectorIterator &operator=(
const MemoryVectorIterator &) =
default;
130 Vc_ALWAYS_INLINE
void *orderBy()
const {
return d; }
132 Vc_ALWAYS_INLINE difference_type
operator-(
const MemoryVectorIterator &rhs)
const {
return d - rhs.d; }
133 Vc_ALWAYS_INLINE reference operator[](
size_t i)
const {
return d[i]; }
134 Vc_ALWAYS_INLINE reference
operator*()
const {
return *d; }
135 Vc_ALWAYS_INLINE pointer operator->()
const {
return d; }
136 Vc_ALWAYS_INLINE MemoryVectorIterator &operator++() { ++d;
return *
this; }
137 Vc_ALWAYS_INLINE MemoryVectorIterator operator++(
int) { MemoryVectorIterator r(*
this); ++d;
return r; }
138 Vc_ALWAYS_INLINE MemoryVectorIterator &operator--() { --d;
return *
this; }
139 Vc_ALWAYS_INLINE MemoryVectorIterator operator--(
int) { MemoryVectorIterator r(*
this); --d;
return r; }
140 Vc_ALWAYS_INLINE MemoryVectorIterator &operator+=(
size_t n) { d += n;
return *
this; }
141 Vc_ALWAYS_INLINE MemoryVectorIterator &operator-=(
size_t n) { d -= n;
return *
this; }
142 Vc_ALWAYS_INLINE MemoryVectorIterator
operator+(
size_t n)
const {
return MemoryVectorIterator(d + n); }
143 Vc_ALWAYS_INLINE MemoryVectorIterator
operator-(
size_t n)
const {
return MemoryVectorIterator(d - n); }
146 template<
typename V,
typename FlagsL,
typename FlagsR>
147 Vc_ALWAYS_INLINE
bool operator==(
const MemoryVectorIterator<V, FlagsL> &l,
const MemoryVectorIterator<V, FlagsR> &r)
149 return l.orderBy() == r.orderBy();
151 template<
typename V,
typename FlagsL,
typename FlagsR>
152 Vc_ALWAYS_INLINE
bool operator!=(
const MemoryVectorIterator<V, FlagsL> &l,
const MemoryVectorIterator<V, FlagsR> &r)
154 return l.orderBy() != r.orderBy();
156 template<
typename V,
typename FlagsL,
typename FlagsR>
157 Vc_ALWAYS_INLINE
bool operator>=(
const MemoryVectorIterator<V, FlagsL> &l,
const MemoryVectorIterator<V, FlagsR> &r)
159 return l.orderBy() >= r.orderBy();
161 template<
typename V,
typename FlagsL,
typename FlagsR>
162 Vc_ALWAYS_INLINE
bool operator<=(const MemoryVectorIterator<V, FlagsL> &l,
const MemoryVectorIterator<V, FlagsR> &r)
164 return l.orderBy() <= r.orderBy();
166 template<
typename V,
typename FlagsL,
typename FlagsR>
167 Vc_ALWAYS_INLINE
bool operator> (
const MemoryVectorIterator<V, FlagsL> &l,
const MemoryVectorIterator<V, FlagsR> &r)
169 return l.orderBy() > r.orderBy();
171 template<
typename V,
typename FlagsL,
typename FlagsR>
172 Vc_ALWAYS_INLINE
bool operator< (const MemoryVectorIterator<V, FlagsL> &l,
const MemoryVectorIterator<V, FlagsR> &r)
174 return l.orderBy() < r.orderBy();
177 #undef Vc_MEM_OPERATOR_EQ 179 #define Vc_VPH_OPERATOR(op) \ 180 template <typename V1, typename Flags1, typename V2, typename Flags2> \ 181 decltype(std::declval<V1>() op std::declval<V2>()) operator op( \ 182 const MemoryVector<V1, Flags1> &x, const MemoryVector<V2, Flags2> &y) \ 184 return x.value() op y.value(); \ 186 Vc_ALL_ARITHMETICS(Vc_VPH_OPERATOR);
187 Vc_ALL_BINARY (Vc_VPH_OPERATOR);
188 Vc_ALL_COMPARES (Vc_VPH_OPERATOR);
189 #undef Vc_VPH_OPERATOR 191 template<
typename V,
typename Parent,
typename Flags = Prefetch<>>
class MemoryRange
198 MemoryRange(Parent *p,
size_t firstIndex,
size_t lastIndex)
199 : m_parent(p), m_first(firstIndex), m_last(lastIndex)
202 MemoryVectorIterator<V, Flags> begin()
const {
return &m_parent->vector(m_first , Flags()); }
203 MemoryVectorIterator<V, Flags> end()
const {
return &m_parent->vector(m_last + 1, Flags()); }
205 template<
typename V,
typename Parent,
int Dimension,
typename RowMemory>
class MemoryDimensionBase;
206 template<
typename V,
typename Parent,
typename RowMemory>
class MemoryDimensionBase<V, Parent, 1, RowMemory>
209 Parent *p() {
return static_cast<Parent *
>(
this); }
210 const Parent *p()
const {
return static_cast<const Parent *
>(
this); }
215 typedef typename V::EntryType EntryType;
220 Vc_ALWAYS_INLINE Vc_PURE EntryType *entries() {
return &p()->m_mem[0]; }
222 Vc_ALWAYS_INLINE Vc_PURE
const EntryType *entries()
const {
return &p()->m_mem[0]; }
227 Vc_ALWAYS_INLINE Vc_PURE EntryType &scalar(
size_t i) {
return entries()[i]; }
229 Vc_ALWAYS_INLINE Vc_PURE
const EntryType scalar(
size_t i)
const {
return entries()[i]; }
236 Vc_ALWAYS_INLINE Vc_PURE
operator EntryType*() {
return entries(); }
238 Vc_ALWAYS_INLINE Vc_PURE
operator const EntryType*()
const {
return entries(); }
242 template <
typename T,
243 typename std::enable_if<
244 std::is_same<typename std::remove_const<T>::type, EntryType *>::value ||
245 std::is_same<typename std::remove_const<T>::type,
void *>::value,
247 Vc_ALWAYS_INLINE Vc_PURE
operator T()
251 template <
typename T,
252 typename std::enable_if<std::is_same<T, const EntryType *>::value ||
253 std::is_same<T, const void *>::value,
255 Vc_ALWAYS_INLINE Vc_PURE
operator T()
const 264 template<
typename Flags>
265 Vc_ALWAYS_INLINE MemoryRange<V, Parent, Flags> range(
size_t firstIndex,
size_t lastIndex, Flags) {
266 return MemoryRange<V, Parent, Flags>(p(), firstIndex, lastIndex);
268 Vc_ALWAYS_INLINE MemoryRange<V, Parent> range(
size_t firstIndex,
size_t lastIndex) {
269 return MemoryRange<V, Parent>(p(), firstIndex, lastIndex);
271 template<
typename Flags>
272 Vc_ALWAYS_INLINE MemoryRange<const V, Parent, Flags> range(
size_t firstIndex,
size_t lastIndex, Flags)
const {
273 return MemoryRange<const V, Parent, Flags>(p(), firstIndex, lastIndex);
275 Vc_ALWAYS_INLINE MemoryRange<const V, Parent> range(
size_t firstIndex,
size_t lastIndex)
const {
276 return MemoryRange<const V, Parent>(p(), firstIndex, lastIndex);
282 Vc_ALWAYS_INLINE EntryType &operator[](
size_t i) {
return entries()[i]; }
284 Vc_ALWAYS_INLINE
const EntryType &operator[](
size_t i)
const {
return entries()[i]; }
297 template<
typename IndexT> Vc_ALWAYS_INLINE Vc_PURE V operator[](
Vector<IndexT> i)
const 299 return V(entries(), i);
302 template<
typename V,
typename Parent,
typename RowMemory>
class MemoryDimensionBase<V, Parent, 2, RowMemory>
305 Parent *p() {
return static_cast<Parent *
>(
this); }
306 const Parent *p()
const {
return static_cast<const Parent *
>(
this); }
311 typedef typename V::EntryType EntryType;
313 static constexpr
size_t rowCount() {
return Parent::RowCount; }
318 Vc_ALWAYS_INLINE Vc_PURE EntryType *entries(
size_t x = 0) {
return &p()->m_mem[x][0]; }
320 Vc_ALWAYS_INLINE Vc_PURE
const EntryType *entries(
size_t x = 0)
const {
return &p()->m_mem[x][0]; }
325 Vc_ALWAYS_INLINE Vc_PURE EntryType &scalar(
size_t i,
size_t j) {
return entries(i)[j]; }
327 Vc_ALWAYS_INLINE Vc_PURE
const EntryType scalar(
size_t i,
size_t j)
const {
return entries(i)[j]; }
332 Vc_ALWAYS_INLINE Vc_PURE RowMemory &operator[](
size_t i) {
333 #ifdef Vc_RECURSIVE_MEMORY 334 return p()->m_mem[i];
336 return RowMemory::fromRawData(entries(i));
340 Vc_ALWAYS_INLINE Vc_PURE
const RowMemory &operator[](
size_t i)
const {
341 #ifdef Vc_RECURSIVE_MEMORY 342 return p()->m_mem[i];
344 return RowMemory::fromRawData(const_cast<EntryType *>(entries(i)));
353 Vc_ALWAYS_INLINE Vc_PURE
size_t rowsCount()
const {
return p()->rowsCount(); }
367 template<
typename V,
typename Parent,
int Dimension,
typename RowMemory>
class MemoryBase :
public MemoryDimensionBase<V, Parent, Dimension, RowMemory>
370 "Vc::Memory can only be used for data-parallel types storing a number " 371 "of values that's a multiple of the memory alignment.");
374 Parent *p() {
return static_cast<Parent *
>(
this); }
375 const Parent *p()
const {
return static_cast<const Parent *
>(
this); }
377 template <
class Flags>
378 using vector_reference = MayAlias<MemoryVector<V, Flags>> &;
379 template <
class Flags>
380 using const_vector_reference =
const MayAlias<MemoryVector<const V, Flags>> &;
392 Vc_ALWAYS_INLINE Vc_PURE
size_t entriesCount()
const {
return p()->entriesCount(); }
397 Vc_ALWAYS_INLINE Vc_PURE
size_t vectorsCount()
const {
return p()->vectorsCount(); }
399 using MemoryDimensionBase<V, Parent, Dimension, RowMemory>::entries;
400 using MemoryDimensionBase<V, Parent, Dimension, RowMemory>::scalar;
405 template<
typename Flags = AlignedTag>
406 Vc_ALWAYS_INLINE MemoryVectorIterator< V, Flags>
begin(Flags flags = Flags()) {
return &firstVector(flags); }
408 template<
typename Flags = AlignedTag>
409 Vc_ALWAYS_INLINE MemoryVectorIterator<const V, Flags>
begin(Flags flags = Flags())
const {
return &firstVector(flags); }
414 template<
typename Flags = AlignedTag>
415 Vc_ALWAYS_INLINE MemoryVectorIterator< V, Flags>
end(Flags flags = Flags()) {
return &lastVector(flags) + 1; }
417 template<
typename Flags = AlignedTag>
418 Vc_ALWAYS_INLINE MemoryVectorIterator<const V, Flags>
end(Flags flags = Flags())
const {
return &lastVector(flags) + 1; }
440 template <
typename Flags = AlignedTag>
441 Vc_ALWAYS_INLINE Vc_PURE
442 typename std::enable_if<!std::is_convertible<Flags, int>::value,
443 vector_reference<Flags>>::type
454 template <
typename Flags = AlignedTag>
455 Vc_ALWAYS_INLINE Vc_PURE
456 typename std::enable_if<!std::is_convertible<Flags, int>::value,
457 const_vector_reference<Flags>>::type
482 template <
typename Flags = UnalignedTag>
483 Vc_ALWAYS_INLINE Vc_PURE vector_reference<Flags>
vectorAt(
size_t i,
484 Flags flags = Flags())
499 template <
typename Flags = UnalignedTag>
500 Vc_ALWAYS_INLINE Vc_PURE const_vector_reference<Flags>
vectorAt(
501 size_t i, Flags flags = Flags())
const 533 template <
typename ShiftT,
typename Flags = decltype(Unaligned)>
534 Vc_ALWAYS_INLINE Vc_PURE
typename std::enable_if<
535 std::is_convertible<ShiftT, int>::value,
536 vector_reference<decltype(std::declval<Flags>() |
Unaligned)>>::type
537 vector(
size_t i, ShiftT shift, Flags = Flags())
539 return *aliasing_cast<
541 &entries()[i * V::Size + shift]);
544 template <
typename ShiftT,
typename Flags = decltype(Unaligned)>
545 Vc_ALWAYS_INLINE Vc_PURE
typename std::enable_if<
546 std::is_convertible<ShiftT, int>::value,
547 const_vector_reference<decltype(std::declval<Flags>() |
Unaligned)>>::type
548 vector(
size_t i, ShiftT shift, Flags = Flags())
const 550 return *aliasing_cast<
552 &entries()[i * V::Size + shift]);
560 template <
typename Flags = AlignedTag>
561 Vc_ALWAYS_INLINE Vc_PURE vector_reference<Flags>
firstVector(Flags f = Flags())
566 template <
typename Flags = AlignedTag>
567 Vc_ALWAYS_INLINE Vc_PURE const_vector_reference<Flags>
firstVector(
568 Flags f = Flags())
const 578 template <
typename Flags = AlignedTag>
579 Vc_ALWAYS_INLINE Vc_PURE vector_reference<Flags>
lastVector(Flags f = Flags())
581 return vector(vectorsCount() - 1, f);
584 template <
typename Flags = AlignedTag>
585 Vc_ALWAYS_INLINE Vc_PURE const_vector_reference<Flags>
lastVector(
586 Flags f = Flags())
const 588 return vector(vectorsCount() - 1, f);
591 Vc_ALWAYS_INLINE Vc_PURE V gather(
const unsigned char *indexes)
const {
return V(entries(),
typename V::IndexType(indexes,
Vc::Unaligned)); }
592 Vc_ALWAYS_INLINE Vc_PURE V gather(
const unsigned short *indexes)
const {
return V(entries(),
typename V::IndexType(indexes,
Vc::Unaligned)); }
593 Vc_ALWAYS_INLINE Vc_PURE V gather(
const unsigned int *indexes)
const {
return V(entries(),
typename V::IndexType(indexes,
Vc::Unaligned)); }
594 Vc_ALWAYS_INLINE Vc_PURE V gather(
const unsigned long *indexes)
const {
return V(entries(),
typename V::IndexType(indexes,
Vc::Unaligned)); }
601 for (
size_t i = 0; i < vectorsCount(); ++i) {
611 for (
size_t i = 0; i < vectorsCount(); ++i) {
612 vector(i) = std::forward<U>(x);
619 template<
typename P2,
typename RM>
622 for (
size_t i = 0; i < vectorsCount(); ++i) {
625 return static_cast<Parent &
>(*this);
631 template<
typename P2,
typename RM>
634 for (
size_t i = 0; i < vectorsCount(); ++i) {
637 return static_cast<Parent &
>(*this);
643 template<
typename P2,
typename RM>
646 for (
size_t i = 0; i < vectorsCount(); ++i) {
649 return static_cast<Parent &
>(*this);
655 template<
typename P2,
typename RM>
658 for (
size_t i = 0; i < vectorsCount(); ++i) {
661 return static_cast<Parent &
>(*this);
669 for (
size_t i = 0; i < vectorsCount(); ++i) {
672 return static_cast<Parent &
>(*this);
680 for (
size_t i = 0; i < vectorsCount(); ++i) {
683 return static_cast<Parent &
>(*this);
691 for (
size_t i = 0; i < vectorsCount(); ++i) {
694 return static_cast<Parent &
>(*this);
702 for (
size_t i = 0; i < vectorsCount(); ++i) {
705 return static_cast<Parent &
>(*this);
711 template<
typename P2,
typename RM>
714 for (
size_t i = 0; i < vectorsCount(); ++i) {
725 template<
typename P2,
typename RM>
728 for (
size_t i = 0; i < vectorsCount(); ++i) {
739 template<
typename P2,
typename RM>
740 inline bool operator<(const MemoryBase<V, P2, Dimension, RM> &rhs)
const {
741 assert(vectorsCount() == rhs.vectorsCount());
742 for (
size_t i = 0; i < vectorsCount(); ++i) {
743 if (!(V(
vector(i)) < V(rhs.vector(i))).isFull()) {
753 template<
typename P2,
typename RM>
754 inline bool operator<=(const MemoryBase<V, P2, Dimension, RM> &rhs)
const {
755 assert(vectorsCount() == rhs.vectorsCount());
756 for (
size_t i = 0; i < vectorsCount(); ++i) {
757 if (!(V(
vector(i)) <= V(rhs.vector(i))).isFull()) {
767 template<
typename P2,
typename RM>
770 for (
size_t i = 0; i < vectorsCount(); ++i) {
781 template<
typename P2,
typename RM>
784 for (
size_t i = 0; i < vectorsCount(); ++i) {
795 template <
typename V,
806 for (; i < vectorsCount; i += 4) {
807 const V tmp3 = src.
vector(i - 3);
808 const V tmp2 = src.
vector(i - 2);
809 const V tmp1 = src.
vector(i - 1);
810 const V tmp0 = src.
vector(i - 0);
816 for (i -= 3; i < vectorsCount; ++i) {
825 #endif // VC_COMMON_MEMORYBASE_H_ bool operator==(const MemoryBase< V, P2, Dimension, RM > &rhs) const
(Inefficient) shorthand compare equality of two arrays.
V::EntryType EntryType
The type of the scalar entries in the array.
The main vector class for expressing data parallelism.
std::enable_if<!std::is_convertible< Flags, int >::value, vector_reference< Flags > >::type vector(size_t i, Flags=Flags())
size_t vectorsCount() const
vector_reference< Flags > vectorAt(size_t i, Flags flags=Flags())
std::enable_if< std::is_convertible< ShiftT, int >::value, const_vector_reference< decltype(std::declval< Flags >)|Unaligned)> >::type vector(size_t i, ShiftT shift, Flags=Flags()) const
Const overload of the above function.
result_vector_type< L, R > operator-(L &&lhs, R &&rhs)
Applies - component-wise and concurrently.
result_vector_type< L, R >::mask_type operator!=(L &&lhs, R &&rhs)
Applies != component-wise and concurrently.
Parent & operator-=(const MemoryBase< V, P2, Dimension, RM > &rhs)
(Inefficient) shorthand to subtract two arrays.
result_vector_type< L, R > operator*(L &&lhs, R &&rhs)
Applies * component-wise and concurrently.
void setZero()
Zero the whole memory area.
Parent & operator+=(const MemoryBase< V, P2, Dimension, RM > &rhs)
(Inefficient) shorthand to add up two arrays.
MemoryVectorIterator< const V, Flags > begin(Flags flags=Flags()) const
const overload of the above
Parent & operator/=(const MemoryBase< V, P2, Dimension, RM > &rhs)
(Inefficient) shorthand to divide two arrays.
Parent & operator*=(EntryType rhs)
(Inefficient) shorthand to multiply a value to an array.
vector_reference< Flags > lastVector(Flags f=Flags())
std::enable_if<!std::is_convertible< Flags, int >::value, const_vector_reference< Flags > >::type vector(size_t i, Flags=Flags()) const
Const overload of the above function.
Common interface to all Memory classes, independent of allocation on the stack or heap...
std::enable_if< std::is_convertible< ShiftT, int >::value, vector_reference< decltype(std::declval< Flags >)|Unaligned)> >::type vector(size_t i, ShiftT shift, Flags=Flags())
bool operator>(const MemoryBase< V, P2, Dimension, RM > &rhs) const
(Inefficient) shorthand compare two arrays.
Helper class for the Memory::vector(size_t) class of functions.
result_vector_type< L, R >::mask_type operator==(L &&lhs, R &&rhs)
Applies == component-wise and concurrently.
vector_reference< Flags > firstVector(Flags f=Flags())
result_vector_type< L, R > operator+(L &&lhs, R &&rhs)
Applies + component-wise and concurrently.
MemoryVectorIterator< V, Flags > begin(Flags flags=Flags())
Return a (vectorized) iterator to the start of this memory object.
bool operator>=(const MemoryBase< V, P2, Dimension, RM > &rhs) const
(Inefficient) shorthand compare two arrays.
Parent & operator/=(EntryType rhs)
(Inefficient) shorthand to divide an array with a value.
const_vector_reference< Flags > lastVector(Flags f=Flags()) const
Const overload of the above function.
const_vector_reference< Flags > vectorAt(size_t i, Flags flags=Flags()) const
Const overload of the above function.
MemoryVectorIterator< V, Flags > end(Flags flags=Flags())
Return a (vectorized) iterator to the end of this memory object.
Parent & operator+=(EntryType rhs)
(Inefficient) shorthand to add a value to an array.
result_vector_type< L, R >::mask_type operator>=(L &&lhs, R &&rhs)
Applies >= component-wise and concurrently.
const_vector_reference< Flags > firstVector(Flags f=Flags()) const
Const overload of the above function.
constexpr VectorSpecialInitializerZero Zero
The special object Vc::Zero can be used to construct Vector and Mask objects initialized to zero/fals...
Common::AdaptSubscriptOperator< std::vector< T, Allocator > > vector
An adapted std::vector container with an additional subscript operator which implements gather and sc...
MemoryVectorIterator< const V, Flags > end(Flags flags=Flags()) const
const overload of the above
result_vector_type< L, R >::mask_type operator>(L &&lhs, R &&rhs)
Applies > component-wise and concurrently.
bool operator!=(const MemoryBase< V, P2, Dimension, RM > &rhs) const
(Inefficient) shorthand compare two arrays.
constexpr std::size_t MemoryAlignment
Specifies the most conservative memory alignment necessary for aligned loads and stores of Vector typ...
Parent & operator*=(const MemoryBase< V, P2, Dimension, RM > &rhs)
(Inefficient) shorthand to multiply two arrays.
Parent & operator=(U &&x)
Assign a value to all vectors in the array.
Parent & operator-=(EntryType rhs)
(Inefficient) shorthand to subtract a value from an array.
size_t entriesCount() const
constexpr UnalignedTag Unaligned
Use this object for a flags parameter to request unaligned loads and stores.