29 #ifndef VC_COMMON_MEMORYBASE_H_
30 #define VC_COMMON_MEMORYBASE_H_
33 #include <type_traits>
37 namespace Vc_VERSIONED_NAMESPACE
42 #define Vc_MEM_OPERATOR_EQ(op) \
43 template<typename T> \
44 Vc_ALWAYS_INLINE enable_if_mutable<T, MemoryVector &> operator op##=(const T &x) { \
45 const V v = value() op x; \
46 v.store(&m_data[0], Flags()); \
58 template<
typename _V,
typename Flags>
class MemoryVector
60 typedef typename std::remove_cv<_V>::type V;
62 template<
typename T,
typename R>
using enable_if_mutable =
63 typename std::enable_if<std::is_same<T, T>::value && !std::is_const<_V>::value, R>::type;
65 typedef typename V::EntryType EntryType;
66 typedef typename V::Mask Mask;
68 EntryType m_data[V::Size];
72 Vc_ALWAYS_INLINE MemoryVector() {}
76 MemoryVector(
const MemoryVector &) =
delete;
77 MemoryVector(MemoryVector &&) =
delete;
82 Vc_ALWAYS_INLINE Vc_PURE V value()
const {
return V(&m_data[0], Flags()); }
89 Vc_ALWAYS_INLINE Vc_PURE
operator V()
const {
return value(); }
92 Vc_ALWAYS_INLINE enable_if_mutable<T, MemoryVector &> operator=(
const T &x) {
95 v.store(&m_data[0], Flags());
99 Vc_ALL_BINARY(Vc_MEM_OPERATOR_EQ)
100 Vc_ALL_ARITHMETICS(Vc_MEM_OPERATOR_EQ)
103 template<typename _V, typename Flags> class MemoryVectorIterator
105 typedef typename std::remove_cv<_V>::type V;
107 template<
typename T,
typename R>
using enable_if_mutable =
108 typename std::enable_if<std::is_same<T, T>::value && !std::is_const<_V>::value, R>::type;
110 using iterator_traits = std::iterator_traits<MemoryVector<_V, Flags> *>;
112 MemoryVector<_V, Flags> *d;
114 typedef typename iterator_traits::difference_type difference_type;
115 typedef typename iterator_traits::value_type value_type;
116 typedef typename iterator_traits::pointer pointer;
117 typedef typename iterator_traits::reference reference;
118 typedef typename iterator_traits::iterator_category iterator_category;
120 constexpr MemoryVectorIterator(MemoryVector<_V, Flags> *dd) : d(dd) {}
121 constexpr MemoryVectorIterator(
const MemoryVectorIterator &) =
default;
122 constexpr MemoryVectorIterator(MemoryVectorIterator &&) =
default;
123 Vc_ALWAYS_INLINE MemoryVectorIterator &operator=(
const MemoryVectorIterator &) =
default;
125 Vc_ALWAYS_INLINE
void *orderBy()
const {
return d; }
127 Vc_ALWAYS_INLINE difference_type operator-(
const MemoryVectorIterator &rhs)
const {
return d - rhs.d; }
128 Vc_ALWAYS_INLINE reference operator[](
size_t i)
const {
return d[i]; }
129 Vc_ALWAYS_INLINE reference operator*()
const {
return *d; }
130 Vc_ALWAYS_INLINE pointer operator->()
const {
return d; }
131 Vc_ALWAYS_INLINE MemoryVectorIterator &operator++() { ++d;
return *
this; }
132 Vc_ALWAYS_INLINE MemoryVectorIterator operator++(
int) { MemoryVectorIterator r(*
this); ++d;
return r; }
133 Vc_ALWAYS_INLINE MemoryVectorIterator &operator--() { --d;
return *
this; }
134 Vc_ALWAYS_INLINE MemoryVectorIterator operator--(
int) { MemoryVectorIterator r(*
this); --d;
return r; }
135 Vc_ALWAYS_INLINE MemoryVectorIterator &operator+=(
size_t n) { d += n;
return *
this; }
136 Vc_ALWAYS_INLINE MemoryVectorIterator &operator-=(
size_t n) { d -= n;
return *
this; }
137 Vc_ALWAYS_INLINE MemoryVectorIterator operator+(
size_t n)
const {
return MemoryVectorIterator(d + n); }
138 Vc_ALWAYS_INLINE MemoryVectorIterator operator-(
size_t n)
const {
return MemoryVectorIterator(d - n); }
141 template<
typename V,
typename FlagsL,
typename FlagsR>
142 Vc_ALWAYS_INLINE
bool operator==(
const MemoryVectorIterator<V, FlagsL> &l,
const MemoryVectorIterator<V, FlagsR> &r)
144 return l.orderBy() == r.orderBy();
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();
172 #undef Vc_MEM_OPERATOR_EQ
174 #define Vc_VPH_OPERATOR(op) \
175 template <typename V1, typename Flags1, typename V2, typename Flags2> \
176 decltype(std::declval<V1>() op std::declval<V2>()) operator op( \
177 const MemoryVector<V1, Flags1> &x, const MemoryVector<V2, Flags2> &y) \
179 return x.value() op y.value(); \
181 Vc_ALL_ARITHMETICS(Vc_VPH_OPERATOR)
182 Vc_ALL_BINARY (Vc_VPH_OPERATOR)
183 Vc_ALL_COMPARES (Vc_VPH_OPERATOR)
184 #undef Vc_VPH_OPERATOR
186 template<
typename V,
typename Parent,
typename Flags = Prefetch<>>
class MemoryRange
193 MemoryRange(Parent *p,
size_t firstIndex,
size_t lastIndex)
194 : m_parent(p), m_first(firstIndex), m_last(lastIndex)
197 MemoryVectorIterator<V, Flags> begin()
const {
return &m_parent->vector(m_first , Flags()); }
198 MemoryVectorIterator<V, Flags> end()
const {
return &m_parent->vector(m_last + 1, Flags()); }
200 template<
typename V,
typename Parent,
int Dimension,
typename RowMemory>
class MemoryDimensionBase;
201 template<
typename V,
typename Parent,
typename RowMemory>
class MemoryDimensionBase<V, Parent, 1, RowMemory>
204 Parent *p() {
return static_cast<Parent *
>(
this); }
205 const Parent *p()
const {
return static_cast<const Parent *
>(
this); }
210 typedef typename V::EntryType EntryType;
215 Vc_ALWAYS_INLINE Vc_PURE EntryType *entries() {
return &p()->m_mem[0]; }
217 Vc_ALWAYS_INLINE Vc_PURE
const EntryType *entries()
const {
return &p()->m_mem[0]; }
222 Vc_ALWAYS_INLINE Vc_PURE EntryType &scalar(
size_t i) {
return entries()[i]; }
224 Vc_ALWAYS_INLINE Vc_PURE
const EntryType scalar(
size_t i)
const {
return entries()[i]; }
231 Vc_ALWAYS_INLINE Vc_PURE
operator EntryType*() {
return entries(); }
233 Vc_ALWAYS_INLINE Vc_PURE
operator const EntryType*()
const {
return entries(); }
237 template <
typename T,
238 typename std::enable_if<
239 std::is_same<typename std::remove_const<T>::type, EntryType *>::value ||
240 std::is_same<typename std::remove_const<T>::type,
void *>::value,
242 Vc_ALWAYS_INLINE Vc_PURE
operator T()
246 template <
typename T,
247 typename std::enable_if<std::is_same<T, const EntryType *>::value ||
248 std::is_same<T, const void *>::value,
250 Vc_ALWAYS_INLINE Vc_PURE
operator T()
const
259 template<
typename Flags>
260 Vc_ALWAYS_INLINE MemoryRange<V, Parent, Flags> range(
size_t firstIndex,
size_t lastIndex, Flags) {
261 return MemoryRange<V, Parent, Flags>(p(), firstIndex, lastIndex);
263 Vc_ALWAYS_INLINE MemoryRange<V, Parent> range(
size_t firstIndex,
size_t lastIndex) {
264 return MemoryRange<V, Parent>(p(), firstIndex, lastIndex);
266 template<
typename Flags>
267 Vc_ALWAYS_INLINE MemoryRange<const V, Parent, Flags> range(
size_t firstIndex,
size_t lastIndex, Flags)
const {
268 return MemoryRange<const V, Parent, Flags>(p(), firstIndex, lastIndex);
270 Vc_ALWAYS_INLINE MemoryRange<const V, Parent> range(
size_t firstIndex,
size_t lastIndex)
const {
271 return MemoryRange<const V, Parent>(p(), firstIndex, lastIndex);
277 Vc_ALWAYS_INLINE EntryType &operator[](
size_t i) {
return entries()[i]; }
279 Vc_ALWAYS_INLINE
const EntryType &operator[](
size_t i)
const {
return entries()[i]; }
292 template<
typename IndexT> Vc_ALWAYS_INLINE Vc_PURE V operator[](Vector<IndexT> i)
const
294 return V(entries(), i);
297 template<
typename V,
typename Parent,
typename RowMemory>
class MemoryDimensionBase<V, Parent, 2, RowMemory>
300 Parent *p() {
return static_cast<Parent *
>(
this); }
301 const Parent *p()
const {
return static_cast<const Parent *
>(
this); }
306 typedef typename V::EntryType EntryType;
308 static constexpr
size_t rowCount() {
return Parent::RowCount; }
313 Vc_ALWAYS_INLINE Vc_PURE EntryType *entries(
size_t x = 0) {
return &p()->m_mem[x][0]; }
315 Vc_ALWAYS_INLINE Vc_PURE
const EntryType *entries(
size_t x = 0)
const {
return &p()->m_mem[x][0]; }
320 Vc_ALWAYS_INLINE Vc_PURE EntryType &scalar(
size_t i,
size_t j) {
return entries(i)[j]; }
322 Vc_ALWAYS_INLINE Vc_PURE
const EntryType scalar(
size_t i,
size_t j)
const {
return entries(i)[j]; }
327 Vc_ALWAYS_INLINE Vc_PURE RowMemory &operator[](
size_t i) {
328 return RowMemory::fromRawData(entries(i));
331 Vc_ALWAYS_INLINE Vc_PURE
const RowMemory &operator[](
size_t i)
const {
332 return RowMemory::fromRawData(const_cast<EntryType *>(entries(i)));
340 Vc_ALWAYS_INLINE Vc_PURE
size_t rowsCount()
const {
return p()->rowsCount(); }
354 template<
typename V,
typename Parent,
int Dimension,
typename RowMemory>
class MemoryBase :
public MemoryDimensionBase<V, Parent, Dimension, RowMemory>
357 "Vc::Memory can only be used for data-parallel types storing a number "
358 "of values that's a multiple of the memory alignment.");
361 Parent *p() {
return static_cast<Parent *
>(
this); }
362 const Parent *p()
const {
return static_cast<const Parent *
>(
this); }
367 typedef typename V::EntryType EntryType;
373 Vc_ALWAYS_INLINE Vc_PURE
size_t entriesCount()
const {
return p()->entriesCount(); }
378 Vc_ALWAYS_INLINE Vc_PURE
size_t vectorsCount()
const {
return p()->vectorsCount(); }
380 using MemoryDimensionBase<V, Parent, Dimension, RowMemory>::entries;
381 using MemoryDimensionBase<V, Parent, Dimension, RowMemory>::scalar;
386 template<
typename Flags = AlignedTag>
387 Vc_ALWAYS_INLINE MemoryVectorIterator< V, Flags> begin(Flags flags = Flags()) {
return &firstVector(flags); }
389 template<
typename Flags = AlignedTag>
390 Vc_ALWAYS_INLINE MemoryVectorIterator<const V, Flags> begin(Flags flags = Flags())
const {
return &firstVector(flags); }
395 template<
typename Flags = AlignedTag>
396 Vc_ALWAYS_INLINE MemoryVectorIterator< V, Flags> end(Flags flags = Flags()) {
return &lastVector(flags) + 1; }
398 template<
typename Flags = AlignedTag>
399 Vc_ALWAYS_INLINE MemoryVectorIterator<const V, Flags> end(Flags flags = Flags())
const {
return &lastVector(flags) + 1; }
421 template<
typename Flags = AlignedTag>
422 Vc_ALWAYS_INLINE Vc_PURE
typename std::enable_if<!std::is_convertible<Flags, int>::value, MemoryVector<V, Flags>>::type &
vector(
size_t i, Flags = Flags()) {
423 return *
new(&entries()[i * V::Size]) MemoryVector<V, Flags>;
431 template<
typename Flags = AlignedTag>
432 Vc_ALWAYS_INLINE Vc_PURE
typename std::enable_if<!std::is_convertible<Flags, int>::value, MemoryVector<const V, Flags>>::type &
vector(
size_t i, Flags = Flags())
const {
433 return *
new(
const_cast<EntryType *
>(&entries()[i * V::Size])) MemoryVector<const V, Flags>;
455 template<
typename Flags = UnalignedTag>
456 Vc_ALWAYS_INLINE Vc_PURE MemoryVector<V, Flags> &vectorAt(
size_t i, Flags flags = Flags()) {
457 return *
new(&entries()[i]) MemoryVector<V, Flags>;
470 template<
typename Flags = UnalignedTag>
471 Vc_ALWAYS_INLINE Vc_PURE MemoryVector<const V, Flags> &vectorAt(
size_t i, Flags flags = Flags())
const {
472 return *
new(
const_cast<EntryType *
>(&entries()[i])) MemoryVector<const V, Flags>;
502 template <
typename ShiftT,
typename Flags = decltype(Unaligned)>
503 Vc_ALWAYS_INLINE Vc_PURE
typename std::enable_if<
504 std::is_convertible<ShiftT, int>::value,
505 MemoryVector<V, decltype(std::declval<Flags>() |
Unaligned)>>::type &
506 vector(
size_t i, ShiftT shift, Flags = Flags())
508 return *
new (&entries()[i * V::Size + shift])
509 MemoryVector<V, decltype(std::declval<Flags>() |
Unaligned)>;
512 template <
typename ShiftT,
typename Flags = decltype(Unaligned)>
513 Vc_ALWAYS_INLINE Vc_PURE
typename std::enable_if<
514 std::is_convertible<ShiftT, int>::value,
515 MemoryVector<const V, decltype(std::declval<Flags>() |
Unaligned)>>::type &
516 vector(
size_t i, ShiftT shift, Flags = Flags())
const
518 return *
new (
const_cast<EntryType *
>(&entries()[i * V::Size + shift]))
519 MemoryVector<const V, decltype(std::declval<Flags>() |
Unaligned)>;
527 template<
typename Flags = AlignedTag>
532 template<
typename Flags = AlignedTag>
542 template<
typename Flags = AlignedTag>
547 template<
typename Flags = AlignedTag>
552 Vc_ALWAYS_INLINE Vc_PURE V gather(
const unsigned char *indexes)
const {
return V(entries(), indexes); }
553 Vc_ALWAYS_INLINE Vc_PURE V gather(
const unsigned short *indexes)
const {
return V(entries(), indexes); }
554 Vc_ALWAYS_INLINE Vc_PURE V gather(
const unsigned int *indexes)
const {
return V(entries(), indexes); }
555 Vc_ALWAYS_INLINE Vc_PURE V gather(
const unsigned long *indexes)
const {
return V(entries(), indexes); }
560 Vc_ALWAYS_INLINE
void setZero() {
562 for (
size_t i = 0; i < vectorsCount(); ++i) {
571 Vc_ALWAYS_INLINE Parent &operator=(U &&x) {
572 for (
size_t i = 0; i < vectorsCount(); ++i) {
573 vector(i) = std::forward<U>(x);
580 template<
typename P2,
typename RM>
582 assert(vectorsCount() == rhs.vectorsCount());
583 for (
size_t i = 0; i < vectorsCount(); ++i) {
584 vector(i) += rhs.vector(i);
586 return static_cast<Parent &
>(*this);
592 template<
typename P2,
typename RM>
594 assert(vectorsCount() == rhs.vectorsCount());
595 for (
size_t i = 0; i < vectorsCount(); ++i) {
596 vector(i) -= rhs.vector(i);
598 return static_cast<Parent &
>(*this);
604 template<
typename P2,
typename RM>
606 assert(vectorsCount() == rhs.vectorsCount());
607 for (
size_t i = 0; i < vectorsCount(); ++i) {
608 vector(i) *= rhs.vector(i);
610 return static_cast<Parent &
>(*this);
616 template<
typename P2,
typename RM>
618 assert(vectorsCount() == rhs.vectorsCount());
619 for (
size_t i = 0; i < vectorsCount(); ++i) {
620 vector(i) /= rhs.vector(i);
622 return static_cast<Parent &
>(*this);
628 inline Parent &operator+=(EntryType rhs) {
630 for (
size_t i = 0; i < vectorsCount(); ++i) {
633 return static_cast<Parent &
>(*this);
639 inline Parent &operator-=(EntryType rhs) {
641 for (
size_t i = 0; i < vectorsCount(); ++i) {
644 return static_cast<Parent &
>(*this);
650 inline Parent &operator*=(EntryType rhs) {
652 for (
size_t i = 0; i < vectorsCount(); ++i) {
655 return static_cast<Parent &
>(*this);
661 inline Parent &operator/=(EntryType rhs) {
663 for (
size_t i = 0; i < vectorsCount(); ++i) {
666 return static_cast<Parent &
>(*this);
672 template<
typename P2,
typename RM>
674 assert(vectorsCount() == rhs.vectorsCount());
675 for (
size_t i = 0; i < vectorsCount(); ++i) {
676 if (!(V(
vector(i)) == V(rhs.vector(i))).isFull()) {
686 template<
typename P2,
typename RM>
688 assert(vectorsCount() == rhs.vectorsCount());
689 for (
size_t i = 0; i < vectorsCount(); ++i) {
690 if (!(V(
vector(i)) == V(rhs.vector(i))).isEmpty()) {
700 template<
typename P2,
typename RM>
701 inline bool operator<(const MemoryBase<V, P2, Dimension, RM> &rhs)
const {
702 assert(vectorsCount() == rhs.vectorsCount());
703 for (
size_t i = 0; i < vectorsCount(); ++i) {
704 if (!(V(
vector(i)) < V(rhs.vector(i))).isFull()) {
714 template<
typename P2,
typename RM>
715 inline bool operator<=(const MemoryBase<V, P2, Dimension, RM> &rhs)
const {
716 assert(vectorsCount() == rhs.vectorsCount());
717 for (
size_t i = 0; i < vectorsCount(); ++i) {
718 if (!(V(
vector(i)) <= V(rhs.vector(i))).isFull()) {
728 template<
typename P2,
typename RM>
730 assert(vectorsCount() == rhs.vectorsCount());
731 for (
size_t i = 0; i < vectorsCount(); ++i) {
732 if (!(V(
vector(i)) > V(rhs.vector(i))).isFull()) {
742 template<
typename P2,
typename RM>
744 assert(vectorsCount() == rhs.vectorsCount());
745 for (
size_t i = 0; i < vectorsCount(); ++i) {
746 if (!(V(
vector(i)) >= V(rhs.vector(i))).isFull()) {
756 template <
typename V,
762 inline void copyVectors(MemoryBase<V, ParentL, Dimension, RowMemoryL> &dst,
763 const MemoryBase<V, ParentR, Dimension, RowMemoryR> &src)
765 const size_t vectorsCount = dst.vectorsCount();
767 for (; i < vectorsCount; i += 4) {
768 const V tmp3 = src.vector(i - 3);
769 const V tmp2 = src.vector(i - 2);
770 const V tmp1 = src.vector(i - 1);
771 const V tmp0 = src.vector(i - 0);
772 dst.vector(i - 3) = tmp3;
773 dst.vector(i - 2) = tmp2;
774 dst.vector(i - 1) = tmp1;
775 dst.vector(i - 0) = tmp0;
777 for (i -= 3; i < vectorsCount; ++i) {
778 dst.vector(i) = src.vector(i);
786 #endif // VC_COMMON_MEMORYBASE_H_
MemoryVector< const V, Flags > & lastVector(Flags=Flags()) const
Const overload of the above function.
MemoryVector< const V, Flags > & firstVector(Flags=Flags()) const
Const overload of the above function.
Common interface to all Memory classes, independent of allocation on the stack or heap...
Common::AdaptSubscriptOperator< std::vector< T, Allocator >> vector
An adapted std::vector container with an additional subscript operator which implements gather and sc...
Helper class for the Memory::vector(size_t) class of functions.
constexpr VectorSpecialInitializerZero Zero
The special object Vc::Zero can be used to construct Vector and Mask objects initialized to zero/fals...
constexpr std::size_t MemoryAlignment
Specifies the most conservative memory alignment necessary for aligned loads and stores of Vector typ...
constexpr UnalignedTag Unaligned
Use this object for a flags parameter to request unaligned loads and stores.