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[];
68 !std::is_arithmetic<typename std::decay<I>::type>::value>
73 Vc_ALWAYS_INLINE
auto operator[](I &&arg__) -> decltype(subscript_operator(*
this, std::forward<I>(arg__)))
75 return subscript_operator(*
this, std::forward<I>(arg__));
80 typename = enable_if<!std::is_arithmetic<typename std::decay<I>::type>::value>>
81 Vc_ALWAYS_INLINE
auto operator[](I &&arg__) const -> decltype(subscript_operator(*this,
std::forward<I>(arg__)))
83 return subscript_operator(*
this, std::forward<I>(arg__));
87 template <
typename Scale,
typename T>
88 Vc_ALWAYS_INLINE enable_if<Scale::num == Scale::den, Traits::decay<T>> applyScale(T &&x)
90 return std::forward<T>(x);
93 template <
typename Scale,
typename T>
94 Vc_ALWAYS_INLINE enable_if<
95 Scale::num != Scale::den && Traits::has_multiply_operator<T, std::intmax_t>::value,
99 static_assert(Scale::num % Scale::den == 0,
100 "Non-integral index scaling requested. This typically happens only for "
101 "Vc::Scalar on 32-bit for gathers on double. You can work around the "
102 "issue by ensuring that all doubles in the structure are aligned on 8 "
104 constexpr
auto value = Scale::num / Scale::den;
105 Vc_ASSERT(
Vc::all_of((x * value) / value == x));
106 return std::forward<T>(x) * value;
109 template <
typename Scale,
typename T>
110 Vc_ALWAYS_INLINE enable_if<
111 Scale::num != Scale::den && !Traits::has_multiply_operator<T, std::intmax_t>::value,
115 static_assert(Scale::num % Scale::den == 0,
116 "Non-integral index scaling requested. This typically happens only for "
117 "Vc::Scalar on 32-bit for gathers on double. You can work around the "
118 "issue by ensuring that all doubles in the structure are aligned on 8 "
120 constexpr
auto value = Scale::num / Scale::den;
121 for (
size_t i = 0; i < x.size(); ++i) {
122 Vc_ASSERT((x[i] * value) / value == x[i]);
128 template <
typename Scale,
typename T,
typename U,
129 typename = enable_if<Traits::has_multiply_operator<T, std::intmax_t>::value &&
130 Traits::has_addition_operator<T, U>::value>>
131 Vc_ALWAYS_INLINE
typename std::decay<T>::type applyScaleAndAdd(T &&x, U &&y)
133 constexpr
auto value = Scale::num / Scale::den;
135 return std::forward<T>(x) + std::forward<U>(y);
137 return std::forward<T>(x) * value + std::forward<U>(y);
141 typename Scale,
typename T,
typename U,
142 typename = enable_if<
143 !(Traits::has_multiply_operator<T &, std::intmax_t>::value &&
144 Traits::has_addition_operator<T &, decltype(std::declval<U>()[0])>::value) &&
145 Traits::has_subscript_operator<U>::value>>
146 Vc_ALWAYS_INLINE T applyScaleAndAdd(T x, U &&y)
148 constexpr
auto value = Scale::num / Scale::den;
149 for (
size_t i = 0; i < x.size(); ++i) {
153 x[i] = x[i] * value + y[i];
159 template <
typename Scale,
typename T,
typename U>
160 Vc_ALWAYS_INLINE enable_if<!(Traits::has_multiply_operator<T &, std::intmax_t>::value &&
161 Traits::has_addition_operator<T &, U>::value) &&
162 !Traits::has_subscript_operator<U>::value,
164 applyScaleAndAdd(T x, U &&y)
166 constexpr
auto value = Scale::num / Scale::den;
167 for (
size_t i = 0; i < x.size(); ++i) {
171 x[i] = x[i] * value + y;
178 template <std::size_t MinSize,
180 bool = Traits::is_simd_vector<IndexT>::value>
181 struct IndexVectorSizeMatches
182 :
public std::true_type
189 template <std::
size_t MinSize,
typename V>
190 struct IndexVectorSizeMatches<MinSize,
192 true> :
public std::integral_constant<bool, (MinSize <= V::Size)>
196 template <std::size_t MinSize, typename T, std::size_t ArraySize>
197 struct IndexVectorSizeMatches<MinSize,
199 false> : public std::integral_constant<bool, (MinSize <= ArraySize)>
203 template <std::size_t MinSize, typename T, std::size_t ArraySize>
204 struct IndexVectorSizeMatches<MinSize,
205 std::array<T, ArraySize>,
206 false> : public std::integral_constant<bool, (MinSize <= ArraySize)>
210 template <std::size_t MinSize, typename T, std::size_t ArraySize>
211 struct IndexVectorSizeMatches<MinSize,
212 Vc::array<T, ArraySize>,
213 false> : public std::integral_constant<bool, (MinSize <= ArraySize)>
218 template <typename IV>
220 (Traits::is_simd_vector<IV>::value && sizeof(typename IV::EntryType) >= sizeof(int)),
222 convertIndexVector(const IV &indexVector)
229 template <typename IV>
231 (Traits::is_simd_vector<IV>::value && sizeof(typename IV::EntryType) < sizeof(int)),
232 SimdArray<int, IV::Size>>
233 convertIndexVector(const IV &indexVector)
235 return static_cast<SimdArray<int, IV::Size>>(indexVector);
239 template<typename T> using promoted_type = decltype(std::declval<T>() + 1);
243 template <typename T, std::size_t N>
244 enable_if<std::is_integral<T>::value, SimdArray<promoted_type<T>, N>> convertIndexVector(
245 const std::array<T, N> &indexVector)
247 return {std::addressof(indexVector[0]), Vc::Unaligned};
249 template <typename T, std::size_t N>
250 enable_if<std::is_integral<T>::value, SimdArray<promoted_type<T>, N>> convertIndexVector(
251 const Vc::array<T, N> &indexVector)
253 return {std::addressof(indexVector[0]), Vc::Unaligned};
255 template <typename T, std::size_t N>
256 enable_if<std::is_integral<T>::value, SimdArray<promoted_type<T>, N>> convertIndexVector(
257 const T (&indexVector)[N])
259 return SimdArray<promoted_type<T>, N>{std::addressof(indexVector[0]), Vc::Unaligned};
264 template <typename T>
265 enable_if<std::is_pointer<T>::value, void> convertIndexVector(T indexVector) = delete;
269 template <typename T>
270 std::vector<promoted_type<T>> convertIndexVector(
271 const std::initializer_list<T> &indexVector)
273 return {begin(indexVector), end(indexVector)};
277 template <typename T>
278 enable_if<(std::is_integral<T>::value && sizeof(T) >= sizeof(int)), std::vector<T>>
279 convertIndexVector(const std::vector<T> &indexVector)
283 template <typename T>
284 enable_if<(std::is_integral<T>::value && sizeof(T) < sizeof(int)),
285 std::vector<promoted_type<T>>>
286 convertIndexVector(const std::vector<T> &indexVector)
288 return {std::begin(indexVector), std::end(indexVector)};
291 template <typename T, typename = decltype(convertIndexVector(std::declval<T>()))>
292 std::true_type is_valid_indexvector(T &&);
293 std::false_type is_valid_indexvector(...);
297 typename T, typename IndexVector, typename Scale = std::ratio<1, 1>,
298 bool = decltype(is_valid_indexvector(std::declval<const IndexVector &>()))::value>
299 class SubscriptOperation
301 const IndexVector m_indexes;
303 using ScalarType = typename std::decay<T>::type;
305 using IndexVectorScaled = Traits::decay<decltype(convertIndexVector(std::declval<const IndexVector &>()))>;
308 template <typename U,
309 typename = enable_if<((std::is_convertible<const U &, IndexVector>::value ||
310 std::is_same<U, IndexVector>::value) &&
311 std::is_copy_constructible<IndexVector>::value)>>
312 constexpr Vc_ALWAYS_INLINE SubscriptOperation(T *address, const U &indexes)
313 : m_indexes(indexes), m_address(address)
317 template <std::size_t... Indexes>
318 constexpr Vc_ALWAYS_INLINE SubscriptOperation(T *address, const IndexVector &indexes,
319 index_sequence<Indexes...>)
320 : m_indexes{indexes[Indexes]...}, m_address(address)
323 template <typename U>
324 constexpr Vc_ALWAYS_INLINE SubscriptOperation(
325 T *address, const U &indexes,
326 enable_if<((std::is_convertible<const U &, IndexVector>::value ||
327 std::is_same<U, IndexVector>::value) &&
328 !std::is_copy_constructible<IndexVector>::value &&
329 std::is_array<IndexVector>::value &&
330 std::extent<IndexVector>::value > 0)> = nullarg)
331 : SubscriptOperation(address, indexes,
332 make_index_sequence<std::extent<IndexVector>::value>())
336 Vc_ALWAYS_INLINE GatherArguments<T, IndexVectorScaled> gatherArguments() const
338 static_assert(std::is_arithmetic<ScalarType>::value,
339 "Incorrect type for a SIMD vector gather. Must be an arithmetic type.");
340 return {applyScale<Scale>(convertIndexVector(m_indexes)), m_address};
343 Vc_ALWAYS_INLINE ScatterArguments<T, IndexVectorScaled> scatterArguments() const
345 static_assert(std::is_arithmetic<ScalarType>::value,
346 "Incorrect type for a SIMD vector scatter. Must be an arithmetic type.");
347 return {applyScale<Scale>(convertIndexVector(m_indexes)), m_address};
350 template <typename V,
351 typename = enable_if<(std::is_arithmetic<ScalarType>::value &&Traits::is_simd_vector<
352 V>::value &&IndexVectorSizeMatches<V::Size, IndexVector>::value)>>
353 Vc_ALWAYS_INLINE operator V() const
355 static_assert(std::is_arithmetic<ScalarType>::value,
356 "Incorrect type for a SIMD vector gather. Must be an arithmetic type.");
357 const auto indexes = applyScale<Scale>(convertIndexVector(m_indexes));
358 return V(m_address, indexes);
361 template <typename V,
362 typename = enable_if<(std::is_arithmetic<ScalarType>::value &&Traits::is_simd_vector<
363 V>::value &&IndexVectorSizeMatches<V::Size, IndexVector>::value)>>
364 Vc_ALWAYS_INLINE SubscriptOperation &operator=(const V &rhs)
366 static_assert(std::is_arithmetic<ScalarType>::value,
367 "Incorrect type for a SIMD vector scatter. Must be an arithmetic type.");
368 const auto indexes = applyScale<Scale>(convertIndexVector(m_indexes));
369 rhs.scatter(m_address, indexes);
379 typename = enable_if<std::is_same<S, typename std::remove_cv<T>::type>::value &&(
380 std::is_class<T>::value || std::is_union<T>::value)>>
381 Vc_ALWAYS_INLINE auto operator[](U S::*member)
382 -> SubscriptOperation<
383 typename std::conditional<std::is_const<T>::value,
384 const typename std::remove_reference<U>::type,
385 typename std::remove_reference<U>::type>::type,
392 std::ratio_multiply<Scale, std::ratio<sizeof(S), sizeof(U)>>>
394 static_assert(std::is_same<Traits::decay<decltype(m_address->*member)>,
395 Traits::decay<U>>::value,
396 "Type mismatch that should be impossible.");
398 return {&(m_address->*member), m_indexes};
422 Vc_ALWAYS_INLINE auto
423 operator[](enable_if<
424 #ifndef Vc_IMPROVE_ERROR_MESSAGES
425 Traits::has_no_allocated_data<T>::value &&
426 Traits::has_subscript_operator<T>::value &&
428 std::is_same<T, U>::value,
430 -> SubscriptOperation<
434 typename std::remove_reference<decltype(m_address[0][index])>::type,
436 std::ratio_multiply<Scale,
437 std::ratio<sizeof(T), sizeof(m_address[0][index])>>>
439 static_assert(Traits::has_subscript_operator<T>::value,
440 "The subscript operator was called on a type that does not implement it.\n");
441 static_assert(Traits::has_no_allocated_data<T>::value,
442 "Invalid container type in gather/scatter operation.\nYou may only use "
443 "nested containers that store the data inside the object (such as builtin "
444 "arrays or std::array) but not containers that store data in allocated "
445 "memory (such as std::vector).\nSince this feature cannot be queried "
446 "generically at compile time you need to spezialize the "
447 "Vc::Traits::has_no_allocated_data_impl<T> type-trait for custom types that "
448 "meet the requirements.\n");
449 static_assert(std::is_lvalue_reference<decltype(m_address[0][index])>::value,
450 "The container does not return an lvalue reference to the data at "
451 "the requested offset. This makes it impossible to execute a "
452 "gather operation.\n");
453 return {&(m_address[0][index]), m_indexes};
457 template <
typename IT>
458 Vc_ALWAYS_INLINE enable_if<
459 #ifndef Vc_IMPROVE_ERROR_MESSAGES
460 Traits::has_no_allocated_data<T>::value &&Traits::has_subscript_operator<T>::value &&
462 Traits::has_subscript_operator<IT>::value,
464 typename std::remove_reference<
465 decltype(m_address[0][std::declval<const IT &>()[0]]
473 operator[](
const IT &index)
475 static_assert(Traits::has_subscript_operator<T>::value,
476 "The subscript operator was called on a type that does not implement it.\n");
477 static_assert(Traits::has_no_allocated_data<T>::value,
478 "Invalid container type in gather/scatter operation.\nYou may only use "
479 "nested containers that store the data inside the object (such as builtin "
480 "arrays or std::array) but not containers that store data in allocated "
481 "memory (such as std::vector).\nSince this feature cannot be queried "
482 "generically at compile time you need to spezialize the "
483 "Vc::Traits::has_no_allocated_data_impl<T> type-trait for custom types that "
484 "meet the requirements.\n");
485 return {&(m_address[0][0]),
486 applyScaleAndAdd<std::ratio_multiply<
487 Scale, std::ratio<
sizeof(T),
sizeof(m_address[0][0])>>>(
488 convertIndexVector(m_indexes), index)};
493 template <
typename T,
typename IndexVector,
typename Scale>
494 class SubscriptOperation<T, IndexVector, Scale, false>;
499 typename IndexVector,
500 typename = enable_if<
501 Traits::has_subscript_operator<IndexVector>::value
503 &&Traits::has_contiguous_storage<Container>::value
507 &&std::is_lvalue_reference<decltype(*begin(std::declval<
508 Container>()))>::value
512 Vc_ALWAYS_INLINE SubscriptOperation<
513 typename std::remove_reference<decltype(*begin(std::declval<Container>()))>::
519 typename std::remove_const<
typename std::remove_reference<
520 IndexVector>::type>::type
523 > subscript_operator(Container &&c, IndexVector &&indexes)
525 Vc_ASSERT(std::addressof(*begin(c)) + 1 ==
526 std::addressof(*(begin(c) + 1)));
530 return {std::addressof(*begin(c)), std::forward<IndexVector>(indexes)};
534 static_assert(!Traits::has_subscript_operator<SubscriptOperation<
int[100][100],
const int *>,
int>::value,
"");
535 static_assert(!Traits::has_subscript_operator<SubscriptOperation<
int[100][100],
const int *>,
int[4]>::value,
"");
536 static_assert(!Traits::has_subscript_operator<SubscriptOperation<std::vector<int>,
const int *>,
int[4]>::value,
"");
537 static_assert( Traits::has_subscript_operator<SubscriptOperation<
int[100][100],
const int[4]>,
int>::value,
"");
538 static_assert( Traits::has_subscript_operator<SubscriptOperation<
int[100][100],
const int[4]>,
int[4]>::value,
"");
539 static_assert(!Traits::has_subscript_operator<SubscriptOperation<std::vector<int>,
const int[4]>,
int[4]>::value,
"");
550 template <
typename Container,
typename I>
551 Vc_ALWAYS_INLINE Vc::Common::SubscriptOperation<
552 typename std::remove_reference<decltype(std::declval<Container>()[0])>::type,
553 const std::initializer_list<I> &> subscript_operator(Container &&vec,
554 const std::initializer_list<I> &indexes)
556 return {&vec[0], indexes};
562 using Common::subscript_operator;
566 template <
typename T,
typename IndexVector,
typename Scale>
567 struct is_subscript_operation_internal<Common::SubscriptOperation<T, IndexVector, Scale>> :
public std::true_type
572 using Common::subscript_operator;
576 #endif // VC_COMMON_SUBSCRIPT_H_
constexpr bool all_of(const Mask &m)
Returns whether all entries in the mask m are true.