29 #ifndef VC_COMMON_SUBSCRIPT_H_
30 #define VC_COMMON_SUBSCRIPT_H_
32 #include <initializer_list>
34 #include <type_traits>
40 namespace Vc_VERSIONED_NAMESPACE
45 template <
typename Base>
class AdaptSubscriptOperator :
public Base
49 template <
typename... Args>
50 Vc_ALWAYS_INLINE AdaptSubscriptOperator(Args &&... arguments)
51 : Base(
std::forward<Args>(arguments)...)
57 Vc_ALWAYS_INLINE AdaptSubscriptOperator(std::initializer_list<T> l)
63 using Base::operator[];
67 typename = enable_if<!std::is_arithmetic<
68 typename std::decay<I>::type>::value>
73 Vc_ALWAYS_INLINE
auto operator[](I &&arg_)
74 -> decltype(subscript_operator(*
this, std::forward<I>(arg_)))
76 return subscript_operator(*
this, std::forward<I>(arg_));
80 template <
typename I,
typename = enable_if<
81 !std::is_arithmetic<typename std::decay<I>::type>::value>>
82 Vc_ALWAYS_INLINE
auto operator[](I &&arg_) const
83 -> decltype(subscript_operator(*this,
std::forward<I>(arg_)))
85 return subscript_operator(*
this, std::forward<I>(arg_));
89 template <
typename Scale,
typename T>
90 Vc_ALWAYS_INLINE enable_if<Scale::num == Scale::den, Traits::decay<T>> applyScale(T &&x)
92 return std::forward<T>(x);
95 template <
typename Scale,
typename T>
96 Vc_ALWAYS_INLINE enable_if<
97 Scale::num != Scale::den && Traits::has_multiply_operator<T, std::intmax_t>::value,
101 static_assert(Scale::num % Scale::den == 0,
102 "Non-integral index scaling requested. This typically happens only for "
103 "Vc::Scalar on 32-bit for gathers on double. You can work around the "
104 "issue by ensuring that all doubles in the structure are aligned on 8 "
106 constexpr
auto value = Scale::num / Scale::den;
107 Vc_ASSERT(
Vc::all_of((x * value) / value == x));
108 return std::forward<T>(x) * value;
111 template <
typename Scale,
typename T>
112 Vc_ALWAYS_INLINE enable_if<
113 Scale::num != Scale::den && !Traits::has_multiply_operator<T, std::intmax_t>::value,
117 static_assert(Scale::num % Scale::den == 0,
118 "Non-integral index scaling requested. This typically happens only for "
119 "Vc::Scalar on 32-bit for gathers on double. You can work around the "
120 "issue by ensuring that all doubles in the structure are aligned on 8 "
122 constexpr
auto value = Scale::num / Scale::den;
123 for (
size_t i = 0; i < x.size(); ++i) {
124 Vc_ASSERT((x[i] * value) / value == x[i]);
130 template <
typename Scale,
typename T,
typename U,
131 typename = enable_if<Traits::has_multiply_operator<T, std::intmax_t>::value &&
132 Traits::has_addition_operator<T, U>::value>>
133 Vc_ALWAYS_INLINE
typename std::decay<T>::type applyScaleAndAdd(T &&x, U &&y)
135 constexpr
auto value = Scale::num / Scale::den;
137 return std::forward<T>(x) + std::forward<U>(y);
139 return std::forward<T>(x) * value + std::forward<U>(y);
143 typename Scale,
typename T,
typename U,
144 typename = enable_if<
145 !(Traits::has_multiply_operator<T &, std::intmax_t>::value &&
146 Traits::has_addition_operator<T &, decltype(std::declval<U>()[0])>::value) &&
147 Traits::has_subscript_operator<U>::value>>
148 Vc_ALWAYS_INLINE T applyScaleAndAdd(T x, U &&y)
150 constexpr
auto value = Scale::num / Scale::den;
151 for (
size_t i = 0; i < x.size(); ++i) {
155 x[i] = x[i] * value + y[i];
161 template <
typename Scale,
typename T,
typename U>
162 Vc_ALWAYS_INLINE enable_if<!(Traits::has_multiply_operator<T &, std::intmax_t>::value &&
163 Traits::has_addition_operator<T &, U>::value) &&
164 !Traits::has_subscript_operator<U>::value,
166 applyScaleAndAdd(T x, U &&y)
168 constexpr
auto value = Scale::num / Scale::den;
169 for (
size_t i = 0; i < x.size(); ++i) {
173 x[i] = x[i] * value + y;
180 template <std::size_t MinSize,
182 bool = Traits::is_simd_vector<IndexT>::value>
183 struct IndexVectorSizeMatches
184 :
public std::true_type
191 template <std::
size_t MinSize,
typename V>
192 struct IndexVectorSizeMatches<MinSize,
194 true> :
public std::integral_constant<bool, (MinSize <= V::Size)>
198 template <std::size_t MinSize, typename T, std::size_t ArraySize>
199 struct IndexVectorSizeMatches<MinSize,
201 false> : public std::integral_constant<bool, (MinSize <= ArraySize)>
205 template <std::size_t MinSize, typename T, std::size_t ArraySize>
206 struct IndexVectorSizeMatches<MinSize,
207 std::array<T, ArraySize>,
208 false> : public std::integral_constant<bool, (MinSize <= ArraySize)>
212 template <std::size_t MinSize, typename T, std::size_t ArraySize>
213 struct IndexVectorSizeMatches<MinSize,
214 Vc::array<T, ArraySize>,
215 false> : public std::integral_constant<bool, (MinSize <= ArraySize)>
220 template <typename IV>
222 (Traits::is_simd_vector<IV>::value && sizeof(typename IV::EntryType) >= sizeof(int)),
224 convertIndexVector(const IV &indexVector)
231 template <typename IV>
233 (Traits::is_simd_vector<IV>::value && sizeof(typename IV::EntryType) < sizeof(int)),
234 SimdArray<int, IV::Size>>
235 convertIndexVector(const IV &indexVector)
237 return static_cast<SimdArray<int, IV::Size>>(indexVector);
241 template<typename T> using promoted_type = decltype(std::declval<T>() + 1);
245 template <typename T, std::size_t N>
246 enable_if<std::is_integral<T>::value, SimdArray<promoted_type<T>, N>> convertIndexVector(
247 const std::array<T, N> &indexVector)
249 return {std::addressof(indexVector[0]), Vc::Unaligned};
251 template <typename T, std::size_t N>
252 enable_if<std::is_integral<T>::value, SimdArray<promoted_type<T>, N>> convertIndexVector(
253 const Vc::array<T, N> &indexVector)
255 return {std::addressof(indexVector[0]), Vc::Unaligned};
257 template <typename T, std::size_t N>
258 enable_if<std::is_integral<T>::value, SimdArray<promoted_type<T>, N>> convertIndexVector(
259 const T (&indexVector)[N])
261 return SimdArray<promoted_type<T>, N>{std::addressof(indexVector[0]), Vc::Unaligned};
266 template <typename T>
267 enable_if<std::is_pointer<T>::value, void> convertIndexVector(T indexVector) = delete;
271 template <typename T>
272 std::vector<promoted_type<T>> convertIndexVector(
273 const std::initializer_list<T> &indexVector)
275 return {begin(indexVector), end(indexVector)};
279 template <typename T>
280 enable_if<(std::is_integral<T>::value && sizeof(T) >= sizeof(int)), std::vector<T>>
281 convertIndexVector(const std::vector<T> &indexVector)
285 template <typename T>
286 enable_if<(std::is_integral<T>::value && sizeof(T) < sizeof(int)),
287 std::vector<promoted_type<T>>>
288 convertIndexVector(const std::vector<T> &indexVector)
290 return {std::begin(indexVector), std::end(indexVector)};
293 template <typename T, typename = decltype(convertIndexVector(std::declval<T>()))>
294 std::true_type is_valid_indexvector(T &&);
295 std::false_type is_valid_indexvector(...);
299 typename T, typename IndexVector, typename Scale = std::ratio<1, 1>,
300 bool = decltype(is_valid_indexvector(std::declval<const IndexVector &>()))::value>
301 class SubscriptOperation
303 const IndexVector m_indexes;
305 using ScalarType = typename std::decay<T>::type;
307 using IndexVectorScaled = Traits::decay<decltype(convertIndexVector(std::declval<const IndexVector &>()))>;
310 template <typename U,
311 typename = enable_if<((std::is_convertible<const U &, IndexVector>::value ||
312 std::is_same<U, IndexVector>::value) &&
313 std::is_copy_constructible<IndexVector>::value)>>
314 constexpr Vc_ALWAYS_INLINE SubscriptOperation(T *address, const U &indexes)
315 : m_indexes(indexes), m_address(address)
319 template <std::size_t... Indexes>
320 constexpr Vc_ALWAYS_INLINE SubscriptOperation(T *address, const IndexVector &indexes,
321 index_sequence<Indexes...>)
322 : m_indexes{indexes[Indexes]...}, m_address(address)
325 template <typename U>
326 constexpr Vc_ALWAYS_INLINE SubscriptOperation(
327 T *address, const U &indexes,
328 enable_if<((std::is_convertible<const U &, IndexVector>::value ||
329 std::is_same<U, IndexVector>::value) &&
330 !std::is_copy_constructible<IndexVector>::value &&
331 std::is_array<IndexVector>::value &&
332 std::extent<IndexVector>::value > 0)> = nullarg)
333 : SubscriptOperation(address, indexes,
334 make_index_sequence<std::extent<IndexVector>::value>())
338 Vc_ALWAYS_INLINE GatherArguments<T, IndexVectorScaled> gatherArguments() const
340 static_assert(std::is_arithmetic<ScalarType>::value,
341 "Incorrect type for a SIMD vector gather. Must be an arithmetic type.");
342 return {applyScale<Scale>(convertIndexVector(m_indexes)), m_address};
345 Vc_ALWAYS_INLINE ScatterArguments<T, IndexVectorScaled> scatterArguments() const
347 static_assert(std::is_arithmetic<ScalarType>::value,
348 "Incorrect type for a SIMD vector scatter. Must be an arithmetic type.");
349 return {applyScale<Scale>(convertIndexVector(m_indexes)), m_address};
352 template <typename V,
353 typename = enable_if<(std::is_arithmetic<ScalarType>::value &&Traits::is_simd_vector<
354 V>::value &&IndexVectorSizeMatches<V::Size, IndexVector>::value)>>
355 Vc_ALWAYS_INLINE operator V() const
357 static_assert(std::is_arithmetic<ScalarType>::value,
358 "Incorrect type for a SIMD vector gather. Must be an arithmetic type.");
359 const auto indexes = applyScale<Scale>(convertIndexVector(m_indexes));
360 return V(m_address, indexes);
363 template <typename V,
364 typename = enable_if<(std::is_arithmetic<ScalarType>::value &&Traits::is_simd_vector<
365 V>::value &&IndexVectorSizeMatches<V::Size, IndexVector>::value)>>
366 Vc_ALWAYS_INLINE SubscriptOperation &operator=(const V &rhs)
368 static_assert(std::is_arithmetic<ScalarType>::value,
369 "Incorrect type for a SIMD vector scatter. Must be an arithmetic type.");
370 const auto indexes = applyScale<Scale>(convertIndexVector(m_indexes));
371 rhs.scatter(m_address, indexes);
381 typename = enable_if<std::is_same<S, typename std::remove_cv<T>::type>::value &&(
382 std::is_class<T>::value || std::is_union<T>::value)>>
383 Vc_ALWAYS_INLINE auto operator[](U S::*member)
384 -> SubscriptOperation<
385 typename std::conditional<std::is_const<T>::value,
386 const typename std::remove_reference<U>::type,
387 typename std::remove_reference<U>::type>::type,
394 std::ratio_multiply<Scale, std::ratio<sizeof(S), sizeof(U)>>>
396 static_assert(std::is_same<Traits::decay<decltype(m_address->*member)>,
397 Traits::decay<U>>::value,
398 "Type mismatch that should be impossible.");
400 return {&(m_address->*member), m_indexes};
424 Vc_ALWAYS_INLINE auto
425 operator[](enable_if<
426 #ifndef Vc_IMPROVE_ERROR_MESSAGES
427 Traits::has_no_allocated_data<T>::value &&
428 Traits::has_subscript_operator<T>::value &&
430 std::is_same<T, U>::value,
432 -> SubscriptOperation<
436 typename std::remove_reference<decltype(m_address[0][index])>::type,
438 std::ratio_multiply<Scale,
439 std::ratio<sizeof(T), sizeof(m_address[0][index])>>>
441 static_assert(Traits::has_subscript_operator<T>::value,
442 "The subscript operator was called on a type that does not implement it.\n");
443 static_assert(Traits::has_no_allocated_data<T>::value,
444 "Invalid container type in gather/scatter operation.\nYou may only use "
445 "nested containers that store the data inside the object (such as builtin "
446 "arrays or std::array) but not containers that store data in allocated "
447 "memory (such as std::vector).\nSince this feature cannot be queried "
448 "generically at compile time you need to spezialize the "
449 "Vc::Traits::has_no_allocated_data_impl<T> type-trait for custom types that "
450 "meet the requirements.\n");
451 static_assert(std::is_lvalue_reference<decltype(m_address[0][index])>::value,
452 "The container does not return an lvalue reference to the data at "
453 "the requested offset. This makes it impossible to execute a "
454 "gather operation.\n");
455 return {&(m_address[0][index]), m_indexes};
459 template <
typename IT>
460 Vc_ALWAYS_INLINE enable_if<
461 #ifndef Vc_IMPROVE_ERROR_MESSAGES
462 Traits::has_no_allocated_data<T>::value &&Traits::has_subscript_operator<T>::value &&
464 Traits::has_subscript_operator<IT>::value,
466 typename std::remove_reference<
467 decltype(m_address[0][std::declval<const IT &>()[0]]
475 operator[](
const IT &index)
477 static_assert(Traits::has_subscript_operator<T>::value,
478 "The subscript operator was called on a type that does not implement it.\n");
479 static_assert(Traits::has_no_allocated_data<T>::value,
480 "Invalid container type in gather/scatter operation.\nYou may only use "
481 "nested containers that store the data inside the object (such as builtin "
482 "arrays or std::array) but not containers that store data in allocated "
483 "memory (such as std::vector).\nSince this feature cannot be queried "
484 "generically at compile time you need to spezialize the "
485 "Vc::Traits::has_no_allocated_data_impl<T> type-trait for custom types that "
486 "meet the requirements.\n");
487 return {&(m_address[0][0]),
488 applyScaleAndAdd<std::ratio_multiply<
489 Scale, std::ratio<
sizeof(T),
sizeof(m_address[0][0])>>>(
490 convertIndexVector(m_indexes), index)};
495 template <
typename T,
typename IndexVector,
typename Scale>
496 class SubscriptOperation<T, IndexVector, Scale, false>;
501 typename IndexVector,
502 typename = enable_if<
503 Traits::has_subscript_operator<IndexVector>::value
505 &&Traits::has_contiguous_storage<Container>::value
509 &&std::is_lvalue_reference<decltype(*begin(std::declval<
510 Container>()))>::value
514 Vc_ALWAYS_INLINE SubscriptOperation<
515 typename std::remove_reference<decltype(*begin(std::declval<Container>()))>::
521 typename std::remove_const<
typename std::remove_reference<
522 IndexVector>::type>::type
525 > subscript_operator(Container &&c, IndexVector &&indexes)
527 Vc_ASSERT(std::addressof(*begin(c)) + 1 ==
528 std::addressof(*(begin(c) + 1)));
532 return {std::addressof(*begin(c)), std::forward<IndexVector>(indexes)};
536 static_assert(!Traits::has_subscript_operator<SubscriptOperation<
int[100][100],
const int *>,
int>::value,
"");
537 static_assert(!Traits::has_subscript_operator<SubscriptOperation<
int[100][100],
const int *>,
int[4]>::value,
"");
538 static_assert(!Traits::has_subscript_operator<SubscriptOperation<std::vector<int>,
const int *>,
int[4]>::value,
"");
539 static_assert( Traits::has_subscript_operator<SubscriptOperation<
int[100][100],
const int[4]>,
int>::value,
"");
540 static_assert( Traits::has_subscript_operator<SubscriptOperation<
int[100][100],
const int[4]>,
int[4]>::value,
"");
541 static_assert(!Traits::has_subscript_operator<SubscriptOperation<std::vector<int>,
const int[4]>,
int[4]>::value,
"");
552 template <
typename Container,
typename I>
553 Vc_ALWAYS_INLINE Vc::Common::SubscriptOperation<
554 typename std::remove_reference<decltype(std::declval<Container>()[0])>::type,
555 const std::initializer_list<I> &> subscript_operator(Container &&vec,
556 const std::initializer_list<I> &indexes)
558 return {&vec[0], indexes};
564 using Common::subscript_operator;
568 template <
typename T,
typename IndexVector,
typename Scale>
569 struct is_subscript_operation_internal<Common::SubscriptOperation<T, IndexVector, Scale>> :
public std::true_type
574 using Common::subscript_operator;
578 #endif // VC_COMMON_SUBSCRIPT_H_
constexpr bool all_of(const Mask &m)
Returns whether all entries in the mask m are true.