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.