28 #ifndef VC_COMMON_SUBSCRIPT_H_
29 #define VC_COMMON_SUBSCRIPT_H_
31 #include <initializer_list>
33 #include <type_traits>
39 namespace Vc_VERSIONED_NAMESPACE
44 template <
typename Base>
class AdaptSubscriptOperator :
public Base
48 template <
typename... Args>
49 Vc_ALWAYS_INLINE AdaptSubscriptOperator(Args &&... arguments)
50 : Base(
std::forward<Args>(arguments)...)
56 Vc_ALWAYS_INLINE AdaptSubscriptOperator(std::initializer_list<T> l)
62 using Base::operator[];
66 typename = enable_if<!std::is_arithmetic<
67 typename std::decay<I>::type>::value>
72 Vc_ALWAYS_INLINE
auto operator[](I &&arg_)
73 -> decltype(subscript_operator(*
this, std::forward<I>(arg_)))
75 return subscript_operator(*
this, std::forward<I>(arg_));
79 template <
typename I,
typename = enable_if<
80 !std::is_arithmetic<typename std::decay<I>::type>::value>>
81 Vc_ALWAYS_INLINE
auto operator[](I &&arg_) const
82 -> decltype(subscript_operator(*this,
std::forward<I>(arg_)))
84 return subscript_operator(*
this, std::forward<I>(arg_));
88 template <
typename Scale,
typename T>
89 Vc_ALWAYS_INLINE enable_if<Scale::num == Scale::den, Traits::decay<T>> applyScale(T &&x)
91 return std::forward<T>(x);
94 template <
typename Scale,
typename T>
95 Vc_ALWAYS_INLINE enable_if<
96 Scale::num != Scale::den && Traits::has_multiply_operator<T, std::intmax_t>::value,
100 static_assert(Scale::num % Scale::den == 0,
101 "Non-integral index scaling requested. This typically happens only for "
102 "Vc::Scalar on 32-bit for gathers on double. You can work around the "
103 "issue by ensuring that all doubles in the structure are aligned on 8 "
105 constexpr
auto value = Scale::num / Scale::den;
106 Vc_ASSERT(
Vc::all_of((x * value) / value == x));
107 return std::forward<T>(x) * value;
110 template <
typename Scale,
typename T>
111 Vc_ALWAYS_INLINE enable_if<
112 Scale::num != Scale::den && !Traits::has_multiply_operator<T, std::intmax_t>::value,
116 static_assert(Scale::num % Scale::den == 0,
117 "Non-integral index scaling requested. This typically happens only for "
118 "Vc::Scalar on 32-bit for gathers on double. You can work around the "
119 "issue by ensuring that all doubles in the structure are aligned on 8 "
121 constexpr
auto value = Scale::num / Scale::den;
122 for (
size_t i = 0; i < x.size(); ++i) {
123 Vc_ASSERT((x[i] * value) / value == x[i]);
129 template <
typename Scale,
typename T,
typename U,
130 typename = enable_if<Traits::has_multiply_operator<T, std::intmax_t>::value &&
131 Traits::has_addition_operator<T, U>::value>>
132 Vc_ALWAYS_INLINE
typename std::decay<T>::type applyScaleAndAdd(T &&x, U &&y)
134 constexpr
auto value = Scale::num / Scale::den;
136 return std::forward<T>(x) + std::forward<U>(y);
138 return std::forward<T>(x) * value + std::forward<U>(y);
142 typename Scale,
typename T,
typename U,
143 typename = enable_if<
144 !(Traits::has_multiply_operator<T &, std::intmax_t>::value &&
145 Traits::has_addition_operator<T &, decltype(std::declval<U>()[0])>::value) &&
146 Traits::has_subscript_operator<U>::value>>
147 Vc_ALWAYS_INLINE T applyScaleAndAdd(T x, U &&y)
149 constexpr
auto value = Scale::num / Scale::den;
150 for (
size_t i = 0; i < x.size(); ++i) {
154 x[i] = x[i] * value + y[i];
160 template <
typename Scale,
typename T,
typename U>
161 Vc_ALWAYS_INLINE enable_if<!(Traits::has_multiply_operator<T &, std::intmax_t>::value &&
162 Traits::has_addition_operator<T &, U>::value) &&
163 !Traits::has_subscript_operator<U>::value,
165 applyScaleAndAdd(T x, U &&y)
167 constexpr
auto value = Scale::num / Scale::den;
168 for (
size_t i = 0; i < x.size(); ++i) {
172 x[i] = x[i] * value + y;
179 template <std::size_t MinSize,
181 bool = Traits::is_simd_vector<IndexT>::value>
182 struct IndexVectorSizeMatches
183 :
public std::true_type
190 template <std::
size_t MinSize,
typename V>
191 struct IndexVectorSizeMatches<MinSize,
193 true> :
public std::integral_constant<bool, (MinSize <= V::Size)>
197 template <std::size_t MinSize, typename T, std::size_t ArraySize>
198 struct IndexVectorSizeMatches<MinSize,
200 false> : public std::integral_constant<bool, (MinSize <= ArraySize)>
204 template <std::size_t MinSize, typename T, std::size_t ArraySize>
205 struct IndexVectorSizeMatches<MinSize,
206 std::array<T, ArraySize>,
207 false> : public std::integral_constant<bool, (MinSize <= ArraySize)>
211 template <std::size_t MinSize, typename T, std::size_t ArraySize>
212 struct IndexVectorSizeMatches<MinSize,
213 Vc::array<T, ArraySize>,
214 false> : public std::integral_constant<bool, (MinSize <= ArraySize)>
219 template <typename IV>
221 (Traits::is_simd_vector<IV>::value && sizeof(typename IV::EntryType) >= sizeof(int)),
223 convertIndexVector(const IV &indexVector)
230 template <typename IV>
232 (Traits::is_simd_vector<IV>::value && sizeof(typename IV::EntryType) < sizeof(int)),
233 SimdArray<int, IV::Size>>
234 convertIndexVector(const IV &indexVector)
236 return static_cast<SimdArray<int, IV::Size>>(indexVector);
240 template<typename T> using promoted_type = decltype(std::declval<T>() + 1);
244 template <typename T, std::size_t N>
245 enable_if<std::is_integral<T>::value, SimdArray<promoted_type<T>, N>> convertIndexVector(
246 const std::array<T, N> &indexVector)
248 return {std::addressof(indexVector[0]), Vc::Unaligned};
250 template <typename T, std::size_t N>
251 enable_if<std::is_integral<T>::value, SimdArray<promoted_type<T>, N>> convertIndexVector(
252 const Vc::array<T, N> &indexVector)
254 return {std::addressof(indexVector[0]), Vc::Unaligned};
256 template <typename T, std::size_t N>
257 enable_if<std::is_integral<T>::value, SimdArray<promoted_type<T>, N>> convertIndexVector(
258 const T (&indexVector)[N])
260 return SimdArray<promoted_type<T>, N>{std::addressof(indexVector[0]), Vc::Unaligned};
268 template <typename T>
269 enable_if<std::is_pointer<T>::value, void> convertIndexVector(T indexVector) = delete;
274 template <typename T>
275 std::vector<promoted_type<T>> convertIndexVector(
276 const std::initializer_list<T> &indexVector)
278 return {begin(indexVector), end(indexVector)};
282 template <typename T>
283 enable_if<(std::is_integral<T>::value && sizeof(T) >= sizeof(int)), std::vector<T>>
284 convertIndexVector(const std::vector<T> &indexVector)
288 template <typename T>
289 enable_if<(std::is_integral<T>::value && sizeof(T) < sizeof(int)),
290 std::vector<promoted_type<T>>>
291 convertIndexVector(const std::vector<T> &indexVector)
293 return {std::begin(indexVector), std::end(indexVector)};
296 template <typename T>
297 std::true_type is_valid_indexvector(
298 T &&, Traits::decay<decltype(convertIndexVector(std::declval<T>()))> * = nullptr);
299 std::false_type is_valid_indexvector(...);
301 template <typename IndexVector, typename Test = decltype(is_valid_indexvector(std::declval<const IndexVector &>()))>
302 struct is_valid_indexvector_ : public std::integral_constant<bool, Test::value>
304 static_assert(!is_valid_indexvector_<const int *>::value, "Pointer is incorrectly classified as valid index vector type");
305 static_assert( is_valid_indexvector_<const int[4]>::value, "C-Array is incorrectly classified as invalid index vector type");
309 typename T, typename IndexVector, typename Scale = std::ratio<1, 1>,
310 bool = is_valid_indexvector_<IndexVector>::value>
311 class SubscriptOperation
313 const IndexVector m_indexes;
315 using ScalarType = typename std::decay<T>::type;
317 using IndexVectorScaled = Traits::decay<decltype(convertIndexVector(std::declval<const IndexVector &>()))>;
320 template <typename U,
321 typename = enable_if<((std::is_convertible<const U &, IndexVector>::value ||
322 std::is_same<U, IndexVector>::value) &&
323 std::is_copy_constructible<IndexVector>::value)>>
324 constexpr Vc_ALWAYS_INLINE SubscriptOperation(T *address, const U &indexes)
325 : m_indexes(indexes), m_address(address)
329 template <std::size_t... Indexes>
330 constexpr Vc_ALWAYS_INLINE SubscriptOperation(T *address, const IndexVector &indexes,
331 index_sequence<Indexes...>)
332 : m_indexes{indexes[Indexes]...}, m_address(address)
335 template <typename U>
336 constexpr Vc_ALWAYS_INLINE SubscriptOperation(
337 T *address, const U &indexes,
338 enable_if<((std::is_convertible<const U &, IndexVector>::value ||
339 std::is_same<U, IndexVector>::value) &&
340 !std::is_copy_constructible<IndexVector>::value &&
341 std::is_array<IndexVector>::value &&
342 std::extent<IndexVector>::value > 0)> = nullarg)
343 : SubscriptOperation(address, indexes,
344 make_index_sequence<std::extent<IndexVector>::value>())
348 Vc_ALWAYS_INLINE GatherArguments<T, IndexVectorScaled> gatherArguments() const
350 static_assert(std::is_arithmetic<ScalarType>::value,
351 "Incorrect type for a SIMD vector gather. Must be an arithmetic type.");
352 return {applyScale<Scale>(convertIndexVector(m_indexes)), m_address};
355 Vc_ALWAYS_INLINE ScatterArguments<T, IndexVectorScaled> scatterArguments() const
357 static_assert(std::is_arithmetic<ScalarType>::value,
358 "Incorrect type for a SIMD vector scatter. Must be an arithmetic type.");
359 return {applyScale<Scale>(convertIndexVector(m_indexes)), m_address};
362 template <typename V,
363 typename = enable_if<(std::is_arithmetic<ScalarType>::value &&Traits::is_simd_vector<
364 V>::value &&IndexVectorSizeMatches<V::Size, IndexVector>::value)>>
365 Vc_ALWAYS_INLINE operator V() const
367 static_assert(std::is_arithmetic<ScalarType>::value,
368 "Incorrect type for a SIMD vector gather. Must be an arithmetic type.");
369 const auto indexes = applyScale<Scale>(convertIndexVector(m_indexes));
370 return V(m_address, indexes);
373 template <typename V,
374 typename = enable_if<(std::is_arithmetic<ScalarType>::value &&Traits::is_simd_vector<
375 V>::value &&IndexVectorSizeMatches<V::Size, IndexVector>::value)>>
376 Vc_ALWAYS_INLINE SubscriptOperation &operator=(const V &rhs)
378 static_assert(std::is_arithmetic<ScalarType>::value,
379 "Incorrect type for a SIMD vector scatter. Must be an arithmetic type.");
380 const auto indexes = applyScale<Scale>(convertIndexVector(m_indexes));
381 rhs.scatter(m_address, indexes);
391 typename = enable_if<std::is_same<S, typename std::remove_cv<T>::type>::value &&(
392 std::is_class<T>::value || std::is_union<T>::value)>>
393 Vc_ALWAYS_INLINE auto operator[](U S::*member)
394 -> SubscriptOperation<
395 typename std::conditional<std::is_const<T>::value,
396 const typename std::remove_reference<U>::type,
397 typename std::remove_reference<U>::type>::type,
404 std::ratio_multiply<Scale, std::ratio<sizeof(S), sizeof(U)>>>
406 static_assert(std::is_same<Traits::decay<decltype(m_address->*member)>,
407 Traits::decay<U>>::value,
408 "Type mismatch that should be impossible.");
410 return {&(m_address->*member), m_indexes};
435 template <intmax_t N, intmax_t D> struct make_ratio {
436 using type = std::ratio<N, D == 0 ? 1 : D>;
441 template <
typename U>
445 Vc_ALWAYS_INLINE
auto operator[](U index) ->
typename std::enable_if<
446 #ifndef Vc_IMPROVE_ERROR_MESSAGES
447 Traits::has_no_allocated_data<T>::value &&
449 std::is_convertible<U, size_t>::value,
454 typename std::remove_reference<decltype(m_address[0][index])>::type,
458 typename make_ratio<sizeof(T), sizeof(m_address[0][index])>::type>>>::type
460 static_assert(Traits::has_subscript_operator<T>::value,
461 "The subscript operator was called on a type that does not implement it.\n");
462 static_assert(Traits::has_no_allocated_data<T>::value,
463 "Invalid container type in gather/scatter operation.\nYou may only use "
464 "nested containers that store the data inside the object (such as builtin "
465 "arrays or std::array) but not containers that store data in allocated "
466 "memory (such as std::vector).\nSince this feature cannot be queried "
467 "generically at compile time you need to spezialize the "
468 "Vc::Traits::has_no_allocated_data_impl<T> type-trait for custom types that "
469 "meet the requirements.\n");
470 static_assert(std::is_lvalue_reference<decltype(m_address[0][index])>::value,
471 "The container does not return an lvalue reference to the data at "
472 "the requested offset. This makes it impossible to execute a "
473 "gather operation.\n");
474 return {&(m_address[0][index]), m_indexes};
478 template <
typename IT>
479 Vc_ALWAYS_INLINE
typename std::enable_if<
480 #ifndef Vc_IMPROVE_ERROR_MESSAGES
481 Traits::has_no_allocated_data<T>::value &&
482 Traits::has_subscript_operator<T>::value &&
484 Traits::has_subscript_operator<IT>::value,
485 SubscriptOperation<
typename std::remove_reference<decltype(
486 m_address[0][std::declval<
495 operator[](
const IT &index)
497 static_assert(Traits::has_subscript_operator<T>::value,
498 "The subscript operator was called on a type that does not implement it.\n");
499 static_assert(Traits::has_no_allocated_data<T>::value,
500 "Invalid container type in gather/scatter operation.\nYou may only use "
501 "nested containers that store the data inside the object (such as builtin "
502 "arrays or std::array) but not containers that store data in allocated "
503 "memory (such as std::vector).\nSince this feature cannot be queried "
504 "generically at compile time you need to spezialize the "
505 "Vc::Traits::has_no_allocated_data_impl<T> type-trait for custom types that "
506 "meet the requirements.\n");
507 return {&(m_address[0][0]),
508 applyScaleAndAdd<std::ratio_multiply<
509 Scale, std::ratio<
sizeof(T),
sizeof(m_address[0][0])>>>(
510 convertIndexVector(m_indexes), index)};
515 template <
typename T,
typename IndexVector,
typename Scale>
516 class SubscriptOperation<T, IndexVector, Scale, false>;
521 typename IndexVector,
522 typename = enable_if<
523 Traits::has_subscript_operator<IndexVector>::value
525 &&Traits::has_contiguous_storage<Container>::value
529 &&std::is_lvalue_reference<decltype(*begin(std::declval<
530 Container>()))>::value
534 Vc_ALWAYS_INLINE SubscriptOperation<
535 typename std::remove_reference<decltype(*begin(std::declval<Container>()))>::
541 typename std::remove_const<
typename std::remove_reference<
542 IndexVector>::type>::type
545 > subscript_operator(Container &&c, IndexVector &&indexes)
547 Vc_ASSERT(std::addressof(*begin(c)) + 1 ==
548 std::addressof(*(begin(c) + 1)));
552 return {std::addressof(*begin(c)), std::forward<IndexVector>(indexes)};
555 static_assert(!Traits::has_subscript_operator<SubscriptOperation<
int[100][100],
const int *>,
int>::value,
"has_subscript_operator fails");
556 static_assert(!Traits::has_subscript_operator<SubscriptOperation<
int[100][100],
const int *>,
int[4]>::value,
"has_subscript_operator fails");
557 static_assert(!Traits::has_subscript_operator<SubscriptOperation<std::vector<int>,
const int *>,
int[4]>::value,
"has_subscript_operator fails");
558 static_assert( Traits::has_subscript_operator<SubscriptOperation<
int[100][100],
const int[4]>,
int>::value,
"has_subscript_operator fails");
559 static_assert( Traits::has_subscript_operator<SubscriptOperation<
int[100][100],
const int[4]>,
int[4]>::value,
"has_subscript_operator fails");
560 static_assert(!Traits::has_subscript_operator<SubscriptOperation<std::vector<int>,
const int[4]>,
int[4]>::value,
"has_subscript_operator fails");
571 template <
typename Container,
typename I>
572 Vc_ALWAYS_INLINE Vc::Common::SubscriptOperation<
573 typename std::remove_reference<decltype(std::declval<Container>()[0])>::type,
574 const std::initializer_list<I> &> subscript_operator(Container &&vec,
575 const std::initializer_list<I> &indexes)
577 return {&vec[0], indexes};
583 using Common::subscript_operator;
587 template <
typename T,
typename IndexVector,
typename Scale>
588 struct is_subscript_operation_internal<Common::SubscriptOperation<T, IndexVector, Scale>> :
public std::true_type
593 using Common::subscript_operator;
597 #endif // VC_COMMON_SUBSCRIPT_H_
constexpr bool all_of(const Mask &m)
Returns whether all entries in the mask m are true.