28 #ifndef VC_COMMON_INTERLEAVEDMEMORY_H_ 29 #define VC_COMMON_INTERLEAVEDMEMORY_H_ 33 namespace Vc_VERSIONED_NAMESPACE
40 template<
typename V,
typename I,
bool Readonly>
struct InterleavedMemoryAccessBase
45 typedef typename std::conditional<
46 Readonly,
typename std::add_const<typename V::EntryType>::type,
47 typename V::EntryType>::type T;
48 typedef typename V::AsArg VArg;
49 typedef T Ta Vc_MAY_ALIAS;
53 Vc_ALWAYS_INLINE InterleavedMemoryAccessBase(
typename I::AsArg indexes, Ta *data)
54 : m_indexes(indexes), m_data(data)
59 template <
typename... Vs> Vc_INTRINSIC
void deinterleave(Vs &&... vs)
const 65 using Impl = Vc::Detail::InterleaveImpl<V, V::Size, sizeof(V)>;
67 template <
typename T, std::size_t... Indexes>
68 Vc_INTRINSIC
void callInterleave(T &&a, index_sequence<Indexes...>)
78 template <
size_t StructSize,
typename V,
typename I =
typename V::IndexType,
80 struct InterleavedMemoryReadAccess :
public InterleavedMemoryAccessBase<V, I, Readonly>
82 typedef InterleavedMemoryAccessBase<V, I, Readonly> Base;
83 typedef typename Base::Ta Ta;
85 Vc_ALWAYS_INLINE InterleavedMemoryReadAccess(Ta *data,
typename I::AsArg indexes)
86 : Base(StructSize == 1u
94 : StructSize == 16u ? indexes << 4
95 : indexes * I(int(StructSize)),
100 template <
typename T, std::size_t... Indexes>
101 Vc_ALWAYS_INLINE T deinterleave_unpack(index_sequence<Indexes...>)
const 108 template <
typename T,
109 typename = enable_if<(std::is_default_constructible<T>::value &&
110 std::is_same<V, Traits::decay<decltype(std::get<0>(
111 std::declval<T &>()))>>::value)>>
112 Vc_ALWAYS_INLINE
operator T()
const 114 return deinterleave_unpack<T>(make_index_sequence<std::tuple_size<T>::value>());
119 template<
typename I>
struct CheckIndexesUnique
122 static Vc_INTRINSIC
void test(
const I &) {}
124 static void test(
const I &indexes)
126 const I test = indexes.sorted();
127 Vc_ASSERT(I::Size == 1 || (test == test.rotated(1)).isEmpty())
132 template<
size_t S>
struct CheckIndexesUnique<SuccessiveEntries<S> >
134 static Vc_INTRINSIC
void test(
const SuccessiveEntries<S> &) {}
140 template <
size_t StructSize,
typename V,
typename I =
typename V::IndexType>
141 struct InterleavedMemoryAccess :
public InterleavedMemoryReadAccess<StructSize, V, I, false>
143 typedef InterleavedMemoryAccessBase<V, I, false> Base;
144 typedef typename Base::Ta Ta;
146 Vc_ALWAYS_INLINE InterleavedMemoryAccess(Ta *data,
typename I::AsArg indexes)
147 : InterleavedMemoryReadAccess<StructSize, V, I, false>(data, indexes)
149 CheckIndexesUnique<I>::test(indexes);
152 template <
int N> Vc_ALWAYS_INLINE
void operator=(VectorReferenceArray<N, V> &&rhs)
154 static_assert(N <= StructSize,
155 "You_are_trying_to_scatter_more_data_into_the_struct_than_it_has");
156 this->callInterleave(std::move(rhs), make_index_sequence<N>());
158 template <
int N> Vc_ALWAYS_INLINE
void operator=(VectorReferenceArray<N, const V> &&rhs)
160 static_assert(N <= StructSize,
161 "You_are_trying_to_scatter_more_data_into_the_struct_than_it_has");
162 this->callInterleave(std::move(rhs), make_index_sequence<N>());
179 typedef typename std::conditional<std::is_const<S>::value,
180 const typename V::EntryType,
181 typename V::EntryType>::type T;
182 typedef typename V::IndexType I;
183 typedef typename V::AsArg VArg;
184 typedef const I &IndexType;
185 static constexpr std::size_t StructSize =
sizeof(S) /
sizeof(T);
186 using ReadAccess = InterleavedMemoryReadAccess<StructSize, V>;
188 typename std::conditional<std::is_const<T>::value, ReadAccess,
189 InterleavedMemoryAccess<StructSize, V>>::type;
190 using ReadSuccessiveEntries =
191 InterleavedMemoryReadAccess<StructSize, V, SuccessiveEntries<StructSize>>;
192 using AccessSuccessiveEntries =
typename std::conditional<
193 std::is_const<T>::value, ReadSuccessiveEntries,
194 InterleavedMemoryAccess<StructSize, V, SuccessiveEntries<StructSize>>>::type;
195 typedef T Ta Vc_MAY_ALIAS;
198 static_assert(StructSize *
sizeof(T) ==
sizeof(S),
199 "InterleavedMemoryAccess_does_not_support_packed_structs");
208 : m_data(reinterpret_cast<Ta *>(s))
264 template <
typename IT>
265 Vc_ALWAYS_INLINE enable_if<!std::is_convertible<IT, size_t>::value &&
266 std::is_convertible<IT, IndexType>::value &&
267 !std::is_const<S>::value,
271 return Access(m_data, indexes);
275 Vc_ALWAYS_INLINE ReadAccess
operator[](IndexType indexes)
const 277 return ReadAccess(m_data, indexes);
281 Vc_ALWAYS_INLINE ReadAccess
gather(IndexType indexes)
const {
return operator[](indexes); }
316 Vc_ALWAYS_INLINE ReadSuccessiveEntries
operator[](
size_t first)
const 318 return ReadSuccessiveEntries(m_data, first);
321 Vc_ALWAYS_INLINE AccessSuccessiveEntries operator[](
size_t first)
323 return AccessSuccessiveEntries(m_data, first);
344 template <
typename V,
typename S>
351 #endif // VC_COMMON_INTERLEAVEDMEMORY_H_ Common::InterleavedMemoryWrapper< S, V > make_interleave_wrapper(S *s)
Creates an adapter around a given array of structure (AoS) that enables optimized loads...
enable_if<!std::is_convertible< IT, size_t >::value &&std::is_convertible< IT, IndexType >::value &&!std::is_const< S >::value, Access > operator[](IT indexes)
Interleaved scatter/gather access.
Wraps a pointer to memory with convenience functions to access it via vectors.
ReadSuccessiveEntries operator[](size_t first) const
Interleaved access.
ReadAccess operator[](IndexType indexes) const
const overload (gathers only) of the above function
InterleavedMemoryWrapper(S *s)
Constructs the wrapper object.
void deinterleave(V *a, V *b, const M *memory, A align)
std::pair< V, V > interleave(const V &a, const V &b)
Interleaves the entries from a and b into two vectors of the same type.
ReadAccess gather(IndexType indexes) const
alias of the above function