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;
64 typedef typename V::EntryType EntryType;
65 typedef typename V::Mask Mask;
67 EntryType m_data[V::Size];
71 Vc_ALWAYS_INLINE MemoryVector() {}
75 MemoryVector(
const MemoryVector &) =
delete;
76 MemoryVector(MemoryVector &&) =
delete;
81 Vc_ALWAYS_INLINE Vc_PURE V value()
const {
return V(&m_data[0], Flags()); }
88 Vc_ALWAYS_INLINE Vc_PURE
operator V()
const {
return value(); }
91 Vc_ALWAYS_INLINE enable_if_mutable<T, MemoryVector &> operator=(
const T &x) {
94 v.store(&m_data[0], Flags());
98 Vc_ALL_BINARY(Vc_MEM_OPERATOR_EQ);
99 Vc_ALL_ARITHMETICS(Vc_MEM_OPERATOR_EQ);
102 template<
typename _V,
typename Flags>
class MemoryVectorIterator
104 typedef typename std::remove_cv<_V>::type V;
106 template<
typename T,
typename R>
using enable_if_mutable =
107 typename std::enable_if<std::is_same<T, T>::value && !std::is_const<_V>::value, R>::type;
109 using iterator_traits = std::iterator_traits<MemoryVector<_V, Flags> *>;
111 MemoryVector<_V, Flags> *d;
113 typedef typename iterator_traits::difference_type difference_type;
114 typedef typename iterator_traits::value_type value_type;
115 typedef typename iterator_traits::pointer pointer;
116 typedef typename iterator_traits::reference reference;
117 typedef typename iterator_traits::iterator_category iterator_category;
119 constexpr MemoryVectorIterator(MemoryVector<_V, Flags> *dd) : d(dd) {}
120 constexpr MemoryVectorIterator(
const MemoryVectorIterator &) =
default;
121 constexpr MemoryVectorIterator(MemoryVectorIterator &&) =
default;
122 Vc_ALWAYS_INLINE MemoryVectorIterator &operator=(
const MemoryVectorIterator &) =
default;
124 Vc_ALWAYS_INLINE
void *orderBy()
const {
return d; }
126 Vc_ALWAYS_INLINE difference_type
operator-(
const MemoryVectorIterator &rhs)
const {
return d - rhs.d; }
127 Vc_ALWAYS_INLINE reference operator[](
size_t i)
const {
return d[i]; }
128 Vc_ALWAYS_INLINE reference
operator*()
const {
return *d; }
129 Vc_ALWAYS_INLINE pointer operator->()
const {
return d; }
130 Vc_ALWAYS_INLINE MemoryVectorIterator &operator++() { ++d;
return *
this; }
131 Vc_ALWAYS_INLINE MemoryVectorIterator operator++(
int) { MemoryVectorIterator r(*
this); ++d;
return r; }
132 Vc_ALWAYS_INLINE MemoryVectorIterator &operator--() { --d;
return *
this; }
133 Vc_ALWAYS_INLINE MemoryVectorIterator operator--(
int) { MemoryVectorIterator r(*
this); --d;
return r; }
134 Vc_ALWAYS_INLINE MemoryVectorIterator &operator+=(
size_t n) { d += n;
return *
this; }
135 Vc_ALWAYS_INLINE MemoryVectorIterator &operator-=(
size_t n) { d -= n;
return *
this; }
136 Vc_ALWAYS_INLINE MemoryVectorIterator
operator+(
size_t n)
const {
return MemoryVectorIterator(d + n); }
137 Vc_ALWAYS_INLINE MemoryVectorIterator
operator-(
size_t n)
const {
return MemoryVectorIterator(d - n); }
140 template<
typename V,
typename FlagsL,
typename FlagsR>
141 Vc_ALWAYS_INLINE
bool operator==(
const MemoryVectorIterator<V, FlagsL> &l,
const MemoryVectorIterator<V, FlagsR> &r)
143 return l.orderBy() == r.orderBy();
145 template<
typename V,
typename FlagsL,
typename FlagsR>
146 Vc_ALWAYS_INLINE
bool operator!=(
const MemoryVectorIterator<V, FlagsL> &l,
const MemoryVectorIterator<V, FlagsR> &r)
148 return l.orderBy() != r.orderBy();
150 template<
typename V,
typename FlagsL,
typename FlagsR>
151 Vc_ALWAYS_INLINE
bool operator>=(
const MemoryVectorIterator<V, FlagsL> &l,
const MemoryVectorIterator<V, FlagsR> &r)
153 return l.orderBy() >= r.orderBy();
155 template<
typename V,
typename FlagsL,
typename FlagsR>
156 Vc_ALWAYS_INLINE
bool operator<=(const MemoryVectorIterator<V, FlagsL> &l,
const MemoryVectorIterator<V, FlagsR> &r)
158 return l.orderBy() <= r.orderBy();
160 template<
typename V,
typename FlagsL,
typename FlagsR>
161 Vc_ALWAYS_INLINE
bool operator> (
const MemoryVectorIterator<V, FlagsL> &l,
const MemoryVectorIterator<V, FlagsR> &r)
163 return l.orderBy() > r.orderBy();
165 template<
typename V,
typename FlagsL,
typename FlagsR>
166 Vc_ALWAYS_INLINE
bool operator< (const MemoryVectorIterator<V, FlagsL> &l,
const MemoryVectorIterator<V, FlagsR> &r)
168 return l.orderBy() < r.orderBy();
171 #undef Vc_MEM_OPERATOR_EQ
173 #define Vc_VPH_OPERATOR(op) \
174 template <typename V1, typename Flags1, typename V2, typename Flags2> \
175 decltype(std::declval<V1>() op std::declval<V2>()) operator op( \
176 const MemoryVector<V1, Flags1> &x, const MemoryVector<V2, Flags2> &y) \
178 return x.value() op y.value(); \
180 Vc_ALL_ARITHMETICS(Vc_VPH_OPERATOR);
181 Vc_ALL_BINARY (Vc_VPH_OPERATOR);
182 Vc_ALL_COMPARES (Vc_VPH_OPERATOR);
183 #undef Vc_VPH_OPERATOR
185 template<
typename V,
typename Parent,
typename Flags = Prefetch<>>
class MemoryRange
192 MemoryRange(Parent *p,
size_t firstIndex,
size_t lastIndex)
193 : m_parent(p), m_first(firstIndex), m_last(lastIndex)
196 MemoryVectorIterator<V, Flags> begin()
const {
return &m_parent->vector(m_first , Flags()); }
197 MemoryVectorIterator<V, Flags> end()
const {
return &m_parent->vector(m_last + 1, Flags()); }
199 template<
typename V,
typename Parent,
int Dimension,
typename RowMemory>
class MemoryDimensionBase;
200 template<
typename V,
typename Parent,
typename RowMemory>
class MemoryDimensionBase<V, Parent, 1, RowMemory>
203 Parent *p() {
return static_cast<Parent *
>(
this); }
204 const Parent *p()
const {
return static_cast<const Parent *
>(
this); }
209 typedef typename V::EntryType EntryType;
214 Vc_ALWAYS_INLINE Vc_PURE EntryType *entries() {
return &p()->m_mem[0]; }
216 Vc_ALWAYS_INLINE Vc_PURE
const EntryType *entries()
const {
return &p()->m_mem[0]; }
221 Vc_ALWAYS_INLINE Vc_PURE EntryType &scalar(
size_t i) {
return entries()[i]; }
223 Vc_ALWAYS_INLINE Vc_PURE
const EntryType scalar(
size_t i)
const {
return entries()[i]; }
230 Vc_ALWAYS_INLINE Vc_PURE
operator EntryType*() {
return entries(); }
232 Vc_ALWAYS_INLINE Vc_PURE
operator const EntryType*()
const {
return entries(); }
236 template <
typename T,
237 typename std::enable_if<
238 std::is_same<typename std::remove_const<T>::type, EntryType *>::value ||
239 std::is_same<typename std::remove_const<T>::type,
void *>::value,
241 Vc_ALWAYS_INLINE Vc_PURE
operator T()
245 template <
typename T,
246 typename std::enable_if<std::is_same<T, const EntryType *>::value ||
247 std::is_same<T, const void *>::value,
249 Vc_ALWAYS_INLINE Vc_PURE
operator T()
const
258 template<
typename Flags>
259 Vc_ALWAYS_INLINE MemoryRange<V, Parent, Flags> range(
size_t firstIndex,
size_t lastIndex, Flags) {
260 return MemoryRange<V, Parent, Flags>(p(), firstIndex, lastIndex);
262 Vc_ALWAYS_INLINE MemoryRange<V, Parent> range(
size_t firstIndex,
size_t lastIndex) {
263 return MemoryRange<V, Parent>(p(), firstIndex, lastIndex);
265 template<
typename Flags>
266 Vc_ALWAYS_INLINE MemoryRange<const V, Parent, Flags> range(
size_t firstIndex,
size_t lastIndex, Flags)
const {
267 return MemoryRange<const V, Parent, Flags>(p(), firstIndex, lastIndex);
269 Vc_ALWAYS_INLINE MemoryRange<const V, Parent> range(
size_t firstIndex,
size_t lastIndex)
const {
270 return MemoryRange<const V, Parent>(p(), firstIndex, lastIndex);
276 Vc_ALWAYS_INLINE EntryType &operator[](
size_t i) {
return entries()[i]; }
278 Vc_ALWAYS_INLINE
const EntryType &operator[](
size_t i)
const {
return entries()[i]; }
291 template<
typename IndexT> Vc_ALWAYS_INLINE Vc_PURE V operator[](Vector<IndexT> i)
const
293 return V(entries(), i);
296 template<
typename V,
typename Parent,
typename RowMemory>
class MemoryDimensionBase<V, Parent, 2, RowMemory>
299 Parent *p() {
return static_cast<Parent *
>(
this); }
300 const Parent *p()
const {
return static_cast<const Parent *
>(
this); }
305 typedef typename V::EntryType EntryType;
307 static constexpr
size_t rowCount() {
return Parent::RowCount; }
312 Vc_ALWAYS_INLINE Vc_PURE EntryType *entries(
size_t x = 0) {
return &p()->m_mem[x][0]; }
314 Vc_ALWAYS_INLINE Vc_PURE
const EntryType *entries(
size_t x = 0)
const {
return &p()->m_mem[x][0]; }
319 Vc_ALWAYS_INLINE Vc_PURE EntryType &scalar(
size_t i,
size_t j) {
return entries(i)[j]; }
321 Vc_ALWAYS_INLINE Vc_PURE
const EntryType scalar(
size_t i,
size_t j)
const {
return entries(i)[j]; }
326 Vc_ALWAYS_INLINE Vc_PURE RowMemory &operator[](
size_t i) {
327 #ifdef Vc_RECURSIVE_MEMORY
328 return p()->m_mem[i];
330 return RowMemory::fromRawData(entries(i));
334 Vc_ALWAYS_INLINE Vc_PURE
const RowMemory &operator[](
size_t i)
const {
335 #ifdef Vc_RECURSIVE_MEMORY
336 return p()->m_mem[i];
338 return RowMemory::fromRawData(const_cast<EntryType *>(entries(i)));
347 Vc_ALWAYS_INLINE Vc_PURE
size_t rowsCount()
const {
return p()->rowsCount(); }
361 template<
typename V,
typename Parent,
int Dimension,
typename RowMemory>
class MemoryBase :
public MemoryDimensionBase<V, Parent, Dimension, RowMemory>
364 "Vc::Memory can only be used for data-parallel types storing a number "
365 "of values that's a multiple of the memory alignment.");
368 Parent *p() {
return static_cast<Parent *
>(
this); }
369 const Parent *p()
const {
return static_cast<const Parent *
>(
this); }
380 Vc_ALWAYS_INLINE Vc_PURE
size_t entriesCount()
const {
return p()->entriesCount(); }
385 Vc_ALWAYS_INLINE Vc_PURE
size_t vectorsCount()
const {
return p()->vectorsCount(); }
387 using MemoryDimensionBase<V, Parent, Dimension, RowMemory>::entries;
388 using MemoryDimensionBase<V, Parent, Dimension, RowMemory>::scalar;
393 template<
typename Flags = AlignedTag>
394 Vc_ALWAYS_INLINE MemoryVectorIterator< V, Flags>
begin(Flags flags = Flags()) {
return &firstVector(flags); }
396 template<
typename Flags = AlignedTag>
397 Vc_ALWAYS_INLINE MemoryVectorIterator<const V, Flags>
begin(Flags flags = Flags())
const {
return &firstVector(flags); }
402 template<
typename Flags = AlignedTag>
403 Vc_ALWAYS_INLINE MemoryVectorIterator< V, Flags>
end(Flags flags = Flags()) {
return &lastVector(flags) + 1; }
405 template<
typename Flags = AlignedTag>
406 Vc_ALWAYS_INLINE MemoryVectorIterator<const V, Flags>
end(Flags flags = Flags())
const {
return &lastVector(flags) + 1; }
428 template<
typename Flags = AlignedTag>
429 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()) {
438 template<
typename Flags = AlignedTag>
462 template<
typename Flags = UnalignedTag>
477 template<
typename Flags = UnalignedTag>
509 template <
typename ShiftT,
typename Flags = decltype(Unaligned)>
510 Vc_ALWAYS_INLINE Vc_PURE
typename std::enable_if<
511 std::is_convertible<ShiftT, int>::value,
513 vector(
size_t i, ShiftT shift, Flags = Flags())
515 return *
new (&entries()[i * V::Size + shift])
519 template <
typename ShiftT,
typename Flags = decltype(Unaligned)>
520 Vc_ALWAYS_INLINE Vc_PURE
typename std::enable_if<
521 std::is_convertible<ShiftT, int>::value,
523 vector(
size_t i, ShiftT shift, Flags = Flags())
const
525 return *
new (
const_cast<EntryType *
>(&entries()[i * V::Size + shift]))
534 template<
typename Flags = AlignedTag>
539 template<
typename Flags = AlignedTag>
549 template<
typename Flags = AlignedTag>
554 template<
typename Flags = AlignedTag>
559 Vc_ALWAYS_INLINE Vc_PURE V gather(
const unsigned char *indexes)
const {
return V(entries(), indexes); }
560 Vc_ALWAYS_INLINE Vc_PURE V gather(
const unsigned short *indexes)
const {
return V(entries(), indexes); }
561 Vc_ALWAYS_INLINE Vc_PURE V gather(
const unsigned int *indexes)
const {
return V(entries(), indexes); }
562 Vc_ALWAYS_INLINE Vc_PURE V gather(
const unsigned long *indexes)
const {
return V(entries(), indexes); }
569 for (
size_t i = 0; i < vectorsCount(); ++i) {
579 for (
size_t i = 0; i < vectorsCount(); ++i) {
580 vector(i) = std::forward<U>(x);
587 template<
typename P2,
typename RM>
590 for (
size_t i = 0; i < vectorsCount(); ++i) {
593 return static_cast<Parent &
>(*this);
599 template<
typename P2,
typename RM>
602 for (
size_t i = 0; i < vectorsCount(); ++i) {
605 return static_cast<Parent &
>(*this);
611 template<
typename P2,
typename RM>
614 for (
size_t i = 0; i < vectorsCount(); ++i) {
617 return static_cast<Parent &
>(*this);
623 template<
typename P2,
typename RM>
626 for (
size_t i = 0; i < vectorsCount(); ++i) {
629 return static_cast<Parent &
>(*this);
637 for (
size_t i = 0; i < vectorsCount(); ++i) {
640 return static_cast<Parent &
>(*this);
648 for (
size_t i = 0; i < vectorsCount(); ++i) {
651 return static_cast<Parent &
>(*this);
659 for (
size_t i = 0; i < vectorsCount(); ++i) {
662 return static_cast<Parent &
>(*this);
670 for (
size_t i = 0; i < vectorsCount(); ++i) {
673 return static_cast<Parent &
>(*this);
679 template<
typename P2,
typename RM>
682 for (
size_t i = 0; i < vectorsCount(); ++i) {
693 template<
typename P2,
typename RM>
696 for (
size_t i = 0; i < vectorsCount(); ++i) {
707 template<
typename P2,
typename RM>
708 inline bool operator<(const MemoryBase<V, P2, Dimension, RM> &rhs)
const {
709 assert(vectorsCount() == rhs.vectorsCount());
710 for (
size_t i = 0; i < vectorsCount(); ++i) {
711 if (!(V(
vector(i)) < V(rhs.vector(i))).isFull()) {
721 template<
typename P2,
typename RM>
722 inline bool operator<=(const MemoryBase<V, P2, Dimension, RM> &rhs)
const {
723 assert(vectorsCount() == rhs.vectorsCount());
724 for (
size_t i = 0; i < vectorsCount(); ++i) {
725 if (!(V(
vector(i)) <= V(rhs.vector(i))).isFull()) {
735 template<
typename P2,
typename RM>
738 for (
size_t i = 0; i < vectorsCount(); ++i) {
749 template<
typename P2,
typename RM>
752 for (
size_t i = 0; i < vectorsCount(); ++i) {
763 template <
typename V,
769 inline void copyVectors(MemoryBase<V, ParentL, Dimension, RowMemoryL> &dst,
770 const MemoryBase<V, ParentR, Dimension, RowMemoryR> &src)
772 const size_t vectorsCount = dst.vectorsCount();
774 for (; i < vectorsCount; i += 4) {
775 const V tmp3 = src.vector(i - 3);
776 const V tmp2 = src.vector(i - 2);
777 const V tmp1 = src.vector(i - 1);
778 const V tmp0 = src.vector(i - 0);
779 dst.vector(i - 3) = tmp3;
780 dst.vector(i - 2) = tmp2;
781 dst.vector(i - 1) = tmp1;
782 dst.vector(i - 0) = tmp0;
784 for (i -= 3; i < vectorsCount; ++i) {
785 dst.vector(i) = src.vector(i);
793 #endif // VC_COMMON_MEMORYBASE_H_
MemoryVectorIterator< const V, Flags > end(Flags flags=Flags()) const
const overload of the above
V::EntryType EntryType
The type of the scalar entries in the array.
MemoryVector< const V, Flags > & lastVector(Flags=Flags()) const
Const overload of the above function.
size_t vectorsCount() const
result_vector_type< L, R > 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.
MemoryVector< V, Flags > & firstVector(Flags=Flags())
size_t entriesCount() const
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.
MemoryVector< const V, Flags > & firstVector(Flags=Flags()) const
Const overload of the above function.
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.
MemoryVectorIterator< const V, Flags > begin(Flags flags=Flags()) const
const overload of the above
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.
result_vector_type< L, R >::mask_type operator==(L &&lhs, R &&rhs)
Applies == component-wise and concurrently.
result_vector_type< L, R > operator+(L &&lhs, R &&rhs)
Applies + component-wise and concurrently.
MemoryVector< const V, Flags > & vectorAt(size_t i, Flags flags=Flags()) const
Const overload of the above function.
MemoryVectorIterator< V, Flags > begin(Flags flags=Flags())
Return a (vectorized) iterator to the start of this memory object.
std::enable_if<!std::is_convertible< Flags, int >::value, MemoryVector< const V, Flags > >::type & vector(size_t i, Flags=Flags()) const
Const overload of the above function.
Parent & operator/=(EntryType rhs)
(Inefficient) shorthand to divide an array with a value.
bool operator>=(const MemoryBase< V, P2, Dimension, RM > &rhs) const
(Inefficient) shorthand compare two arrays.
MemoryVector< V, Flags > & lastVector(Flags=Flags())
MemoryVector< V, Flags > & vectorAt(size_t i, Flags flags=Flags())
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.
constexpr VectorSpecialInitializerZero Zero
The special object Vc::Zero can be used to construct Vector and Mask objects initialized to zero/fals...
bool operator==(const MemoryBase< V, P2, Dimension, RM > &rhs) const
(Inefficient) shorthand compare equality of two arrays.
result_vector_type< L, R >::mask_type operator>(L &&lhs, R &&rhs)
Applies > component-wise and concurrently.
std::enable_if< std::is_convertible< ShiftT, int >::value, MemoryVector< const V, decltype(std::declval< Flags >)|Unaligned)> >::type & vector(size_t i, ShiftT shift, Flags=Flags()) const
Const overload of the above function.
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.
bool operator!=(const MemoryBase< V, P2, Dimension, RM > &rhs) const
(Inefficient) shorthand compare 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.
std::enable_if< std::is_convertible< ShiftT, int >::value, MemoryVector< V, decltype(std::declval< Flags >)|Unaligned)> >::type & vector(size_t i, ShiftT shift, Flags=Flags())
std::enable_if<!std::is_convertible< Flags, int >::value, MemoryVector< V, Flags > >::type & vector(size_t i, Flags=Flags())
constexpr UnalignedTag Unaligned
Use this object for a flags parameter to request unaligned loads and stores.