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> *>;
117 MemoryVector<_V, Flags> *d;
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;
125 constexpr MemoryVectorIterator(MemoryVector<_V, Flags> *dd) : d(dd) {}
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
446 return *aliasing_cast<MemoryVector<V, Flags>>(&entries()[i * V::Size]);
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
460 return *aliasing_cast<MemoryVector<const V, Flags>>(&entries()[i * V::Size]);
482 template <
typename Flags = UnalignedTag>
483 Vc_ALWAYS_INLINE Vc_PURE vector_reference<Flags>
vectorAt(
size_t i,
484 Flags flags = Flags())
486 return *aliasing_cast<MemoryVector<V, Flags>>(&entries()[i]);
499 template <
typename Flags = UnalignedTag>
500 Vc_ALWAYS_INLINE Vc_PURE const_vector_reference<Flags>
vectorAt(
501 size_t i, Flags flags = Flags())
const
503 return *aliasing_cast<MemoryVector<const V, Flags>>(&entries()[i]);
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>
742 for (
size_t i = 0; i < vectorsCount(); ++i) {
753 template<
typename P2,
typename RM>
756 for (
size_t i = 0; i < vectorsCount(); ++i) {
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,
801 inline void copyVectors(MemoryBase<V, ParentL, Dimension, RowMemoryL> &dst,
802 const MemoryBase<V, ParentR, Dimension, RowMemoryR> &src)
804 const size_t vectorsCount = dst.vectorsCount();
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);
811 dst.vector(i - 3) = tmp3;
812 dst.vector(i - 2) = tmp2;
813 dst.vector(i - 1) = tmp1;
814 dst.vector(i - 0) = tmp0;
816 for (i -= 3; i < vectorsCount; ++i) {
817 dst.vector(i) = src.vector(i);
825 #endif // VC_COMMON_MEMORYBASE_H_