File indexing completed on 2025-01-30 10:25:50
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028 #ifndef VC_COMMON_SIMDIZE_H_
0029 #define VC_COMMON_SIMDIZE_H_
0030
0031 #include <tuple>
0032 #include <array>
0033
0034 #include "../Allocator"
0035 #include "interleavedmemory.h"
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122 namespace Vc_VERSIONED_NAMESPACE
0123 {
0124
0125
0126
0127
0128
0129
0130 namespace SimdizeDetail
0131 {
0132
0133
0134
0135
0136 using std::is_same;
0137 using std::is_base_of;
0138 using std::false_type;
0139 using std::true_type;
0140 using std::iterator_traits;
0141 using std::conditional;
0142 using std::size_t;
0143
0144
0145
0146
0147
0148 template <typename... Ts> struct Typelist;
0149
0150
0151
0152
0153 enum class Category {
0154
0155 NoTransformation,
0156
0157 ArithmeticVectorizable,
0158
0159 InputIterator,
0160
0161 OutputIterator,
0162
0163 ForwardIterator,
0164
0165 BidirectionalIterator,
0166
0167 RandomAccessIterator,
0168
0169 ClassTemplate
0170 };
0171
0172
0173
0174
0175
0176 template <typename T, typename ItCat = typename T::iterator_category>
0177 constexpr Category iteratorCategories(int, ItCat * = nullptr)
0178 {
0179 return is_base_of<std::random_access_iterator_tag, ItCat>::value
0180 ? Category::RandomAccessIterator
0181 : is_base_of<std::bidirectional_iterator_tag, ItCat>::value
0182 ? Category::BidirectionalIterator
0183 : is_base_of<std::forward_iterator_tag, ItCat>::value
0184 ? Category::ForwardIterator
0185 : is_base_of<std::output_iterator_tag, ItCat>::value
0186 ? Category::OutputIterator
0187 : is_base_of<std::input_iterator_tag, ItCat>::value
0188 ? Category::InputIterator
0189 : Category::NoTransformation;
0190 }
0191
0192
0193
0194 template <typename T>
0195 constexpr enable_if<std::is_pointer<T>::value, Category> iteratorCategories(float)
0196 {
0197 return Category::RandomAccessIterator;
0198 }
0199
0200
0201
0202 template <typename T> constexpr Category iteratorCategories(...)
0203 {
0204 return Category::NoTransformation;
0205 }
0206
0207
0208
0209
0210 template <typename T> struct is_class_template : public false_type
0211 {
0212 };
0213 template <template <typename...> class C, typename... Ts>
0214 struct is_class_template<C<Ts...>> : public true_type
0215 {
0216 };
0217
0218
0219
0220
0221 template <typename T> constexpr Category typeCategory()
0222 {
0223 return (is_same<T, bool>::value || is_same<T, short>::value ||
0224 is_same<T, unsigned short>::value || is_same<T, int>::value ||
0225 is_same<T, unsigned int>::value || is_same<T, float>::value ||
0226 is_same<T, double>::value)
0227 ? Category::ArithmeticVectorizable
0228 : iteratorCategories<T>(int()) != Category::NoTransformation
0229 ? iteratorCategories<T>(int())
0230 : is_class_template<T>::value ? Category::ClassTemplate
0231 : Category::NoTransformation;
0232 }
0233
0234
0235
0236
0237
0238
0239 template <typename T, size_t TupleSize = std::tuple_size<T>::value>
0240 constexpr size_t determine_tuple_size()
0241 {
0242 return TupleSize;
0243 }
0244 template <typename T, size_t TupleSize = T::tuple_size>
0245 constexpr size_t determine_tuple_size(size_t = T::tuple_size)
0246 {
0247 return TupleSize;
0248 }
0249
0250
0251
0252 template <typename T> struct determine_tuple_size_
0253 : public std::integral_constant<size_t, determine_tuple_size<T>()>
0254 {};
0255
0256 namespace
0257 {
0258 template <typename T> struct The_simdization_for_the_requested_type_is_not_implemented;
0259 }
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273 template <typename T, size_t N, typename MT, Category = typeCategory<T>()>
0274 struct ReplaceTypes : public The_simdization_for_the_requested_type_is_not_implemented<T>
0275 {
0276 };
0277
0278
0279
0280
0281
0282 template <typename T, size_t N, typename MT> struct ReplaceTypes<T, N, MT, Category::NoTransformation>
0283 {
0284 typedef T type;
0285 };
0286
0287
0288
0289
0290
0291 template <typename T, size_t N = 0, typename MT = void>
0292 using simdize = typename SimdizeDetail::ReplaceTypes<T, N, MT>::type;
0293
0294
0295 template <class T, size_t N,
0296 class Best = typename Common::select_best_vector_type<T, N>::type>
0297 using deduce_vector_t =
0298 typename std::conditional<Best::size() == N, Best, SimdArray<T, N>>::type;
0299
0300
0301
0302
0303
0304 template <typename T, size_t N, typename MT>
0305 struct ReplaceTypes<T, N, MT, Category::ArithmeticVectorizable>
0306 : public conditional<N == 0, Vector<T>, deduce_vector_t<T, N>> {
0307 };
0308
0309
0310
0311
0312
0313 template <size_t N, typename MT>
0314 struct ReplaceTypes<bool, N, MT, Category::ArithmeticVectorizable>
0315 : public std::enable_if<true, typename ReplaceTypes<MT, N, MT>::type::mask_type> {
0316 };
0317
0318
0319
0320 template <size_t N>
0321 struct ReplaceTypes<bool, N, void, Category::ArithmeticVectorizable>
0322 : public ReplaceTypes<bool, N, float, Category::ArithmeticVectorizable>
0323 {
0324 };
0325
0326
0327
0328
0329
0330
0331
0332 template <size_t N, typename MT, typename Replaced, typename... Remaining>
0333 struct SubstituteOneByOne;
0334
0335
0336
0337
0338
0339 template <size_t N, typename MT, typename... Replaced, typename T,
0340 typename... Remaining>
0341 struct SubstituteOneByOne<N, MT, Typelist<Replaced...>, T, Remaining...>
0342 {
0343 private:
0344
0345
0346
0347
0348 template <typename U, size_t M = U::Size>
0349 static std::integral_constant<size_t, M> size_or_0(int);
0350 template <typename U> static std::integral_constant<size_t, 0> size_or_0(...);
0351
0352
0353 using V = simdize<T, N, MT>;
0354
0355
0356
0357
0358
0359 static constexpr auto NewN = N != 0 ? N : decltype(size_or_0<V>(int()))::value;
0360
0361
0362
0363
0364
0365
0366 typedef conditional_t<(N != NewN && is_same<MT, void>::value),
0367 conditional_t<is_same<T, bool>::value, float, T>, MT> NewMT;
0368
0369 public:
0370
0371
0372
0373 using type = typename SubstituteOneByOne<NewN, NewMT, Typelist<Replaced..., V>,
0374 Remaining...>::type;
0375 };
0376
0377
0378
0379 template <size_t Size, typename... Replaced> struct SubstitutedBase;
0380
0381 template <typename Replaced> struct SubstitutedBase<1, Replaced> {
0382 template <typename ValueT, template <typename, ValueT...> class C, ValueT... Values>
0383 using SubstitutedWithValues = C<Replaced, Values...>;
0384 };
0385
0386 template <typename R0, typename R1> struct SubstitutedBase<2, R0, R1>
0387 {
0388 template <typename ValueT, template <typename, typename, ValueT...> class C,
0389 ValueT... Values>
0390 using SubstitutedWithValues = C<R0, R1, Values...>;
0391 };
0392
0393 template <typename R0, typename R1, typename R2> struct SubstitutedBase<3, R0, R1, R2>
0394 {
0395 template <typename ValueT, template <typename, typename, typename, ValueT...> class C,
0396 ValueT... Values>
0397 using SubstitutedWithValues = C<R0, R1, R2, Values...>;
0398 };
0399 #if defined Vc_ICC || defined Vc_MSVC
0400 #define Vc_VALUE_PACK_EXPANSION_IS_BROKEN 1
0401 #endif
0402
0403 template <typename... Replaced> struct SubstitutedBase<4, Replaced...> {
0404 #ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
0405 template <typename ValueT,
0406 template <typename, typename, typename, typename, ValueT...> class C,
0407 ValueT... Values>
0408 using SubstitutedWithValues = C<Replaced..., Values...>;
0409 #endif
0410 };
0411
0412 template <typename... Replaced> struct SubstitutedBase<5, Replaced...> {
0413 #ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
0414 template <typename ValueT, template <typename, typename, typename, typename, typename,
0415 ValueT...> class C,
0416 ValueT... Values>
0417 using SubstitutedWithValues = C<Replaced..., Values...>;
0418 #endif
0419 };
0420
0421 template <typename... Replaced> struct SubstitutedBase<6, Replaced...> {
0422 #ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
0423 template <typename ValueT, template <typename, typename, typename, typename, typename,
0424 typename, ValueT...> class C,
0425 ValueT... Values>
0426 using SubstitutedWithValues = C<Replaced..., Values...>;
0427 #endif
0428 };
0429
0430 template <typename... Replaced> struct SubstitutedBase<7, Replaced...> {
0431 #ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
0432 template <typename ValueT, template <typename, typename, typename, typename, typename,
0433 typename, typename, ValueT...> class C,
0434 ValueT... Values>
0435 using SubstitutedWithValues = C<Replaced..., Values...>;
0436 #endif
0437 };
0438
0439 template <typename... Replaced> struct SubstitutedBase<8, Replaced...> {
0440 #ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
0441 template <typename ValueT, template <typename, typename, typename, typename, typename,
0442 typename, typename, typename, ValueT...> class C,
0443 ValueT... Values>
0444 using SubstitutedWithValues = C<Replaced..., Values...>;
0445 #endif
0446 };
0447
0448
0449
0450
0451
0452
0453 template <size_t N_, typename MT, typename Replaced0, typename... Replaced>
0454 struct SubstituteOneByOne<N_, MT, Typelist<Replaced0, Replaced...>>
0455 {
0456
0457
0458
0459 struct type
0460 : public SubstitutedBase<sizeof...(Replaced) + 1, Replaced0, Replaced...> {
0461 static constexpr auto N = N_;
0462
0463
0464
0465
0466 template <template <typename...> class C>
0467 using Substituted = C<Replaced0, Replaced...>;
0468 };
0469 };
0470
0471
0472
0473
0474
0475
0476
0477
0478
0479
0480
0481
0482
0483
0484
0485
0486
0487 template <typename Scalar, typename Base, size_t N> class Adapter;
0488
0489
0490
0491
0492
0493 template <template <typename...> class C, typename... Ts, size_t N, typename MT>
0494 struct ReplaceTypes<C<Ts...>, N, MT, Category::ClassTemplate>
0495 {
0496
0497 using SubstitutionResult =
0498 typename SubstituteOneByOne<N, MT, Typelist<>, Ts...>::type;
0499
0500
0501
0502
0503
0504 using Vectorized = typename SubstitutionResult::template Substituted<C>;
0505
0506
0507
0508
0509
0510 using type = conditional_t<is_same<C<Ts...>, Vectorized>::value, C<Ts...>,
0511 Adapter<C<Ts...>, Vectorized, SubstitutionResult::N>>;
0512 };
0513
0514
0515
0516
0517
0518
0519 #ifdef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
0520
0521 #define Vc_DEFINE_NONTYPE_REPLACETYPES_(ValueType_) \
0522 template <template <typename, ValueType_...> class C, typename T, ValueType_ Value0, \
0523 ValueType_... Values> \
0524 struct is_class_template<C<T, Value0, Values...>> : public true_type { \
0525 }; \
0526 template <template <typename, typename, ValueType_...> class C, typename T0, \
0527 typename T1, ValueType_ Value0, ValueType_... Values> \
0528 struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type { \
0529 }; \
0530 template <template <typename, typename, typename, ValueType_...> class C, \
0531 typename T0, typename T1, typename T2, ValueType_ Value0, \
0532 ValueType_... Values> \
0533 struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type { \
0534 }; \
0535 template <template <typename, typename, typename, typename, ValueType_...> class C, \
0536 typename T0, typename T1, typename T2, typename T3, ValueType_ Value0, \
0537 ValueType_... Values> \
0538 struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type { \
0539 }; \
0540 template <template <typename, typename, typename, typename, typename, ValueType_...> \
0541 class C, \
0542 typename T0, typename T1, typename T2, typename T3, typename T4, \
0543 ValueType_ Value0, ValueType_... Values> \
0544 struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
0545 : public true_type { \
0546 }; \
0547 template <template <typename, typename, typename, typename, typename, typename, \
0548 ValueType_...> class C, \
0549 typename T0, typename T1, typename T2, typename T3, typename T4, \
0550 typename T5, ValueType_ Value0, ValueType_... Values> \
0551 struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
0552 : public true_type { \
0553 }; \
0554 template <template <typename, typename, typename, typename, typename, typename, \
0555 typename, ValueType_...> class C, \
0556 typename T0, typename T1, typename T2, typename T3, typename T4, \
0557 typename T5, typename T6, ValueType_ Value0, ValueType_... Values> \
0558 struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
0559 : public true_type { \
0560 }; \
0561 template <template <typename, ValueType_> class C, typename T0, ValueType_ Value0, \
0562 size_t N, typename MT> \
0563 struct ReplaceTypes<C<T0, Value0>, N, MT, Category::ClassTemplate> { \
0564 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
0565 typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
0566 Substituted; \
0567 static constexpr auto NN = tmp::N; \
0568 typedef conditional_t<is_same<C<T0, Value0>, Substituted>::value, C<T0, Value0>, \
0569 Adapter<C<T0, Value0>, Substituted, NN>> type; \
0570 }; \
0571 template <template <typename, typename, ValueType_> class C, typename T0, \
0572 typename T1, ValueType_ Value0, size_t N, typename MT> \
0573 struct ReplaceTypes<C<T0, T1, Value0>, N, MT, Category::ClassTemplate> { \
0574 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
0575 typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
0576 Substituted; \
0577 static constexpr auto NN = tmp::N; \
0578 typedef conditional_t<is_same<C<T0, T1, Value0>, Substituted>::value, \
0579 C<T0, T1, Value0>, \
0580 Adapter<C<T0, T1, Value0>, Substituted, NN>> type; \
0581 }; \
0582 template <template <typename, typename, typename, ValueType_> class C, typename T0, \
0583 typename T1, typename T2, ValueType_ Value0, size_t N, typename MT> \
0584 struct ReplaceTypes<C<T0, T1, T2, Value0>, N, MT, Category::ClassTemplate> { \
0585 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
0586 typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
0587 Substituted; \
0588 static constexpr auto NN = tmp::N; \
0589 typedef conditional_t<is_same<C<T0, T1, T2, Value0>, Substituted>::value, \
0590 C<T0, T1, T2, Value0>, \
0591 Adapter<C<T0, T1, T2, Value0>, Substituted, NN>> type; \
0592 }
0593 #else
0594 #define Vc_DEFINE_NONTYPE_REPLACETYPES_(ValueType_) \
0595 template <template <typename, ValueType_...> class C, typename T, ValueType_ Value0, \
0596 ValueType_... Values> \
0597 struct is_class_template<C<T, Value0, Values...>> : public true_type { \
0598 }; \
0599 template <template <typename, typename, ValueType_...> class C, typename T0, \
0600 typename T1, ValueType_ Value0, ValueType_... Values> \
0601 struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type { \
0602 }; \
0603 template <template <typename, typename, typename, ValueType_...> class C, \
0604 typename T0, typename T1, typename T2, ValueType_ Value0, \
0605 ValueType_... Values> \
0606 struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type { \
0607 }; \
0608 template <template <typename, typename, typename, typename, ValueType_...> class C, \
0609 typename T0, typename T1, typename T2, typename T3, ValueType_ Value0, \
0610 ValueType_... Values> \
0611 struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type { \
0612 }; \
0613 template <template <typename, typename, typename, typename, typename, ValueType_...> \
0614 class C, \
0615 typename T0, typename T1, typename T2, typename T3, typename T4, \
0616 ValueType_ Value0, ValueType_... Values> \
0617 struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
0618 : public true_type { \
0619 }; \
0620 template <template <typename, typename, typename, typename, typename, typename, \
0621 ValueType_...> class C, \
0622 typename T0, typename T1, typename T2, typename T3, typename T4, \
0623 typename T5, ValueType_ Value0, ValueType_... Values> \
0624 struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
0625 : public true_type { \
0626 }; \
0627 template <template <typename, typename, typename, typename, typename, typename, \
0628 typename, ValueType_...> class C, \
0629 typename T0, typename T1, typename T2, typename T3, typename T4, \
0630 typename T5, typename T6, ValueType_ Value0, ValueType_... Values> \
0631 struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
0632 : public true_type { \
0633 }; \
0634 template <template <typename, ValueType_...> class C, typename T0, \
0635 ValueType_ Value0, ValueType_... Values, size_t N, typename MT> \
0636 struct ReplaceTypes<C<T0, Value0, Values...>, N, MT, Category::ClassTemplate> { \
0637 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
0638 typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
0639 Values...> Substituted; \
0640 static constexpr auto NN = tmp::N; \
0641 typedef conditional_t<is_same<C<T0, Value0, Values...>, Substituted>::value, \
0642 C<T0, Value0, Values...>, \
0643 Adapter<C<T0, Value0, Values...>, Substituted, NN>> type; \
0644 }; \
0645 template <template <typename, typename, ValueType_...> class C, typename T0, \
0646 typename T1, ValueType_ Value0, ValueType_... Values, size_t N, \
0647 typename MT> \
0648 struct ReplaceTypes<C<T0, T1, Value0, Values...>, N, MT, Category::ClassTemplate> { \
0649 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
0650 typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
0651 Values...> Substituted; \
0652 static constexpr auto NN = tmp::N; \
0653 typedef conditional_t<is_same<C<T0, T1, Value0, Values...>, Substituted>::value, \
0654 C<T0, T1, Value0, Values...>, \
0655 Adapter<C<T0, T1, Value0, Values...>, Substituted, NN>> \
0656 type; \
0657 }; \
0658 template <template <typename, typename, typename, ValueType_...> class C, \
0659 typename T0, typename T1, typename T2, ValueType_ Value0, \
0660 ValueType_... Values, size_t N, typename MT> \
0661 struct ReplaceTypes<C<T0, T1, T2, Value0, Values...>, N, MT, \
0662 Category::ClassTemplate> { \
0663 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
0664 typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
0665 Values...> Substituted; \
0666 static constexpr auto NN = tmp::N; \
0667 typedef conditional_t< \
0668 is_same<C<T0, T1, T2, Value0, Values...>, Substituted>::value, \
0669 C<T0, T1, T2, Value0, Values...>, \
0670 Adapter<C<T0, T1, T2, Value0, Values...>, Substituted, NN>> type; \
0671 }
0672 #endif
0673 Vc_DEFINE_NONTYPE_REPLACETYPES_(bool);
0674 Vc_DEFINE_NONTYPE_REPLACETYPES_(wchar_t);
0675 Vc_DEFINE_NONTYPE_REPLACETYPES_(char);
0676 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed char);
0677 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned char);
0678 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed short);
0679 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned short);
0680 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed int);
0681 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned int);
0682 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed long);
0683 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned long);
0684 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed long long);
0685 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned long long);
0686 #undef Vc_DEFINE_NONTYPE_REPLACETYPES_
0687
0688
0689 namespace preferred_construction_impl
0690 {
0691 template <typename T> T create();
0692
0693 template <class Type, class... Init, class = decltype(Type(create<Init>()...))>
0694 constexpr std::integral_constant<int, 0> test(int);
0695
0696 template <class Type, class... Init, class = decltype(Type{create<Init>()...})>
0697 constexpr std::integral_constant<int, 1> test(float);
0698
0699 template <class Type, class... Init, class T, class = decltype(Type{{create<Init>()...}})>
0700 constexpr std::integral_constant<int, 2> test(T);
0701
0702 template <class Type, class... Init> constexpr std::integral_constant<int, 3> test(...);
0703 }
0704
0705 template <class Type, class... Init>
0706 constexpr inline decltype(preferred_construction_impl::test<Type, Init...>(0))
0707 preferred_construction()
0708 {
0709 return {};
0710 }
0711
0712
0713
0714
0715
0716
0717
0718 template <size_t I, typename T,
0719 typename R = decltype(std::declval<T &>().template vc_get_<I>())>
0720 R get_dispatcher(T &x, void * = nullptr)
0721 {
0722 return x.template vc_get_<I>();
0723 }
0724 template <size_t I, typename T,
0725 typename R = decltype(std::declval<const T &>().template vc_get_<I>())>
0726 R get_dispatcher(const T &x, void * = nullptr)
0727 {
0728 return x.template vc_get_<I>();
0729 }
0730 template <size_t I, typename T, typename R = decltype(std::get<I>(std::declval<T &>()))>
0731 R get_dispatcher(T &x, int = 0)
0732 {
0733 return std::get<I>(x);
0734 }
0735 template <size_t I, typename T,
0736 typename R = decltype(std::get<I>(std::declval<const T &>()))>
0737 R get_dispatcher(const T &x, int = 0)
0738 {
0739 return std::get<I>(x);
0740 }
0741
0742
0743
0744 template <size_t I, class T, class = void>
0745 struct my_tuple_element : std::tuple_element<I, T> {
0746 };
0747
0748 template <size_t I, class T>
0749 struct my_tuple_element<
0750 I, T, typename std::conditional<
0751 true, void, decltype(std::declval<T>().template vc_get_<I>())>::type> {
0752 using type =
0753 typename std::decay<decltype(std::declval<T>().template vc_get_<I>())>::type;
0754 };
0755
0756
0757
0758
0759
0760
0761
0762
0763 template <class... Ts> struct homogeneous_sizeof;
0764 template <class T, class = void> struct homogeneous_sizeof_one;
0765 template <class T>
0766 struct homogeneous_sizeof_one<T,
0767 typename std::enable_if<std::is_arithmetic<T>::value>::type>
0768 : std::integral_constant<size_t, sizeof(T)> {
0769 };
0770 template <class T0> struct homogeneous_sizeof<T0> : homogeneous_sizeof_one<T0> {
0771 };
0772
0773 template <class T0, class... Ts>
0774 struct homogeneous_sizeof<T0, Ts...>
0775 : std::integral_constant<size_t, homogeneous_sizeof<T0>::value ==
0776 homogeneous_sizeof<Ts...>::value
0777 ? homogeneous_sizeof<T0>::value
0778 : 0> {
0779 };
0780
0781 template <class T, size_t... Is>
0782 std::integral_constant<
0783 size_t, homogeneous_sizeof<typename my_tuple_element<Is, T>::type...>::value>
0784 homogeneous_sizeof_helper(index_sequence<Is...>);
0785
0786 template <class T>
0787 struct homogeneous_sizeof_one<T, typename std::enable_if<std::is_class<T>::value>::type>
0788 : decltype(homogeneous_sizeof_helper<T>(
0789 make_index_sequence<determine_tuple_size_<T>::value>())) {
0790 };
0791
0792
0793
0794 template <typename Scalar, typename Base, size_t N> class Adapter : public Base
0795 {
0796 private:
0797
0798 template <std::size_t... Indexes, int X>
0799 Adapter(Vc::index_sequence<Indexes...>, const Scalar,
0800 std::integral_constant<int, X>)
0801 {
0802 static_assert(
0803 X < 3, "Failed to construct an object of type Base. Neither via "
0804 "parenthesis-init, brace-init, nor double-brace init appear to work.");
0805 }
0806
0807
0808 template <std::size_t... Indexes>
0809 Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_,
0810 std::integral_constant<int, 2>)
0811 : Base{{get_dispatcher<Indexes>(x_)...}}
0812 {
0813 }
0814
0815
0816 template <std::size_t... Indexes>
0817 Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_,
0818 std::integral_constant<int, 1>)
0819 : Base{get_dispatcher<Indexes>(x_)...}
0820 {
0821 }
0822
0823
0824 template <std::size_t... Indexes>
0825 Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_,
0826 std::integral_constant<int, 0>)
0827 : Base(get_dispatcher<Indexes>(x_)...)
0828 {
0829 }
0830
0831 template <std::size_t... Indexes>
0832 Adapter(Vc::index_sequence<Indexes...> seq_, const Scalar &x_)
0833 : Adapter(seq_, x_,
0834 preferred_construction<Base, decltype(get_dispatcher<Indexes>(
0835 std::declval<const Scalar &>()))...>())
0836 {
0837 }
0838
0839 public:
0840
0841 static constexpr size_t size() { return N; }
0842 static constexpr size_t Size = N;
0843
0844
0845 using base_type = Base;
0846
0847
0848 using scalar_type = Scalar;
0849
0850
0851
0852 Adapter() = default;
0853
0854
0855 #if defined Vc_CLANG && Vc_CLANG < 0x30700
0856 Vc_INTRINSIC Adapter(const Adapter &x) : Base(x) {}
0857 #else
0858 Adapter(const Adapter &) = default;
0859 #endif
0860
0861 Adapter(Adapter &&) = default;
0862
0863 Adapter &operator=(const Adapter &) = default;
0864
0865 Adapter &operator=(Adapter &&) = default;
0866
0867
0868 template <typename U, size_t TupleSize = determine_tuple_size_<Scalar>::value,
0869 typename Seq = Vc::make_index_sequence<TupleSize>,
0870 typename = enable_if<std::is_convertible<U, Scalar>::value>>
0871 Adapter(U &&x_)
0872 : Adapter(Seq(), static_cast<const Scalar &>(x_))
0873 {
0874 }
0875
0876
0877 template <class F,
0878 class = decltype(static_cast<Scalar>(std::declval<F>()(
0879 size_t())))>
0880 Adapter(F &&fun);
0881
0882
0883
0884 template <typename A0, typename... Args,
0885 typename = typename std::enable_if<
0886 !Traits::is_index_sequence<A0>::value &&
0887 (sizeof...(Args) > 0 || !std::is_convertible<A0, Scalar>::value)>::type>
0888 Adapter(A0 &&arg0_, Args &&... arguments_)
0889 : Base(std::forward<A0>(arg0_), std::forward<Args>(arguments_)...)
0890 {
0891 }
0892
0893
0894 template <typename T,
0895 typename = decltype(Base(std::declval<const std::initializer_list<T> &>()))>
0896 Adapter(const std::initializer_list<T> &l_)
0897 : Base(l_)
0898 {
0899 }
0900
0901
0902
0903 void *operator new(size_t size)
0904 {
0905 return Vc::Common::aligned_malloc<alignof(Adapter)>(size);
0906 }
0907 void *operator new(size_t, void *p_) { return p_; }
0908 void *operator new[](size_t size)
0909 {
0910 return Vc::Common::aligned_malloc<alignof(Adapter)>(size);
0911 }
0912 void *operator new[](size_t , void *p_) { return p_; }
0913 void operator delete(void *ptr_, size_t) { Vc::Common::free(ptr_); }
0914 void operator delete(void *, void *) {}
0915 void operator delete[](void *ptr_, size_t) { Vc::Common::free(ptr_); }
0916 void operator delete[](void *, void *) {}
0917 };
0918
0919
0920
0921
0922
0923 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
0924 inline void operator==(
0925 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
0926 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
0927 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
0928 inline void operator!=(
0929 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
0930 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
0931 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
0932 inline void operator<=(
0933 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
0934 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
0935 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
0936 inline void operator>=(
0937 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
0938 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
0939 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
0940 inline void operator<(
0941 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
0942 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
0943 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
0944 inline void operator>(
0945 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
0946 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
0947
0948
0949 }
0950 }
0951
0952 namespace std
0953 {
0954
0955
0956
0957 template <typename Scalar, typename Base, size_t N>
0958 class tuple_size<Vc::SimdizeDetail::Adapter<Scalar, Base, N>> : public tuple_size<Base>
0959 {
0960 };
0961
0962
0963
0964 template <size_t I, typename Scalar, typename Base, size_t N>
0965 class tuple_element<I, Vc::SimdizeDetail::Adapter<Scalar, Base, N>>
0966 : public tuple_element<I, Base>
0967 {
0968 };
0969
0970
0971
0972
0973
0974
0975
0976 template <typename S, typename T, size_t N>
0977 class allocator<Vc::SimdizeDetail::Adapter<S, T, N>>
0978 : public Vc::Allocator<Vc::SimdizeDetail::Adapter<S, T, N>>
0979 {
0980 public:
0981 template <typename U> struct rebind
0982 {
0983 typedef std::allocator<U> other;
0984 };
0985 };
0986 }
0987
0988 namespace Vc_VERSIONED_NAMESPACE
0989 {
0990 namespace SimdizeDetail
0991 {
0992
0993
0994
0995
0996
0997
0998
0999
1000 template <typename T> static inline T decay_workaround(const T &x) { return x; }
1001
1002
1003
1004
1005
1006 template <typename S, typename T, size_t N, size_t... Indexes>
1007 inline void assign_impl(Adapter<S, T, N> &a, size_t i, const S &x,
1008 Vc::index_sequence<Indexes...>)
1009 {
1010 const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(x)))...> tmp(
1011 decay_workaround(get_dispatcher<Indexes>(x))...);
1012 auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(tmp), 0)...};
1013 if (&unused == &unused) {}
1014 }
1015
1016 template <class S, class... Args>
1017 S construct(std::integral_constant<int, 0>, Args &&... args)
1018 {
1019 return S(std::forward<Args>(args)...);
1020 }
1021 template <class S, class... Args>
1022 S construct(std::integral_constant<int, 1>, Args &&... args)
1023 {
1024 return S{std::forward<Args>(args)...};
1025 }
1026 template <class S, class... Args>
1027 S construct(std::integral_constant<int, 2>, Args &&... args)
1028 {
1029 return S{{std::forward<Args>(args)...}};
1030 }
1031
1032
1033
1034
1035
1036 template <typename S, typename T, size_t N, size_t... Indexes>
1037 inline S extract_impl(const Adapter<S, T, N> &a, size_t i, Vc::index_sequence<Indexes...>)
1038 {
1039 const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[i]))...> tmp(
1040 decay_workaround(get_dispatcher<Indexes>(a)[i])...);
1041 return construct<S>(
1042 preferred_construction<S, decltype(decay_workaround(
1043 get_dispatcher<Indexes>(a)[i]))...>(),
1044 decay_workaround(get_dispatcher<Indexes>(a)[i])...);
1045
1046 }
1047
1048
1049 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1050 inline Adapter<S, T, N> shifted_impl(const Adapter<S, T, N> &a, int shift,
1051 Vc::index_sequence<Indexes...>)
1052 {
1053 Adapter<S, T, N> r;
1054 auto &&unused = {(get_dispatcher<Indexes>(r) = get_dispatcher<Indexes>(a).shifted(shift), 0)...};
1055 if (&unused == &unused) {}
1056 return r;
1057 }
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068 template <typename S, typename T, size_t N>
1069 inline Adapter<S, T, N> shifted(const Adapter<S, T, N> &a, int shift)
1070 {
1071 return shifted_impl(a, shift, Vc::make_index_sequence<determine_tuple_size<T>()>());
1072 }
1073
1074
1075
1076
1077
1078 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1079 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, S &x,
1080 Vc::index_sequence<Indexes...>)
1081 {
1082 const auto &a_const = a;
1083 const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a_const)[0]))...>
1084 tmp{decay_workaround(get_dispatcher<Indexes>(a_const)[i])...};
1085 auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(x), 0)...};
1086 auto &&unused2 = {(get_dispatcher<Indexes>(x) = get_dispatcher<Indexes>(tmp), 0)...};
1087 if (&unused == &unused2) {}
1088 }
1089 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1090 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b,
1091 std::size_t j, Vc::index_sequence<Indexes...>)
1092 {
1093 const auto &a_const = a;
1094 const auto &b_const = b;
1095 const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a_const)[0]))...>
1096 tmp{decay_workaround(get_dispatcher<Indexes>(a_const)[i])...};
1097 auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(b_const)[j], 0)...};
1098 auto &&unused2 = {(get_dispatcher<Indexes>(b)[j] = get_dispatcher<Indexes>(tmp), 0)...};
1099 if (&unused == &unused2) {}
1100 }
1101
1102
1103
1104
1105
1106
1107 template <typename S, typename T, std::size_t N>
1108 inline void swap(Adapter<S, T, N> &a, std::size_t i, S &x)
1109 {
1110 swap_impl(a, i, x, Vc::make_index_sequence<determine_tuple_size<T>()>());
1111 }
1112 template <typename S, typename T, std::size_t N>
1113 inline void swap(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b, std::size_t j)
1114 {
1115 swap_impl(a, i, b, j, Vc::make_index_sequence<determine_tuple_size<T>()>());
1116 }
1117
1118 template <typename A> class Scalar
1119 {
1120 using reference = typename std::add_lvalue_reference<A>::type;
1121 using S = typename A::scalar_type;
1122 using IndexSeq = Vc::make_index_sequence<determine_tuple_size<S>()>;
1123
1124 public:
1125 Scalar(reference aa, size_t ii) : a(aa), i(ii) {}
1126
1127
1128 Scalar(const Scalar &) = delete;
1129 Scalar(Scalar &&) = delete;
1130 Scalar &operator=(const Scalar &) = delete;
1131 Scalar &operator=(Scalar &&) = delete;
1132
1133 void operator=(const S &x) { assign_impl(a, i, x, IndexSeq()); }
1134 operator S() const { return extract_impl(a, i, IndexSeq()); }
1135
1136 template <typename AA>
1137 friend inline void swap(Scalar<AA> &&a, typename AA::scalar_type &b);
1138 template <typename AA>
1139 friend inline void swap(typename AA::scalar_type &b, Scalar<AA> &&a);
1140 template <typename AA> friend inline void swap(Scalar<AA> &&a, Scalar<AA> &&b);
1141
1142 private:
1143 reference a;
1144 size_t i;
1145 };
1146
1147
1148
1149 template <typename A> inline void swap(Scalar<A> &&a, typename A::scalar_type &b)
1150 {
1151 swap_impl(a.a, a.i, b, typename Scalar<A>::IndexSeq());
1152 }
1153
1154
1155 template <typename A> inline void swap(typename A::scalar_type &b, Scalar<A> &&a)
1156 {
1157 swap_impl(a.a, a.i, b, typename Scalar<A>::IndexSeq());
1158 }
1159
1160 template <typename A> inline void swap(Scalar<A> &&a, Scalar<A> &&b)
1161 {
1162 swap_impl(a.a, a.i, b.a, b.i, typename Scalar<A>::IndexSeq());
1163 }
1164
1165
1166 template <class S, class T, size_t N, size_t... I>
1167 inline void load_interleaved_impl(Vc::index_sequence<I...>, Adapter<S, T, N> &a,
1168 const S *mem)
1169 {
1170 const InterleavedMemoryWrapper<S, decltype(decay_workaround(get_dispatcher<0>(a)))>
1171 wrapper(const_cast<S *>(mem));
1172 Vc::tie(get_dispatcher<I>(a)...) = wrapper[0];
1173 }
1174
1175
1176 template <class S, class T, size_t N, size_t... I>
1177 inline void store_interleaved_impl(Vc::index_sequence<I...>, const Adapter<S, T, N> &a,
1178 S *mem)
1179 {
1180 InterleavedMemoryWrapper<S, decltype(decay_workaround(get_dispatcher<0>(a)))> wrapper(
1181 mem);
1182 wrapper[0] = Vc::tie(get_dispatcher<I>(a)...);
1183 }
1184
1185 template <typename A> class Interface
1186 {
1187 using reference = typename std::add_lvalue_reference<A>::type;
1188 using IndexSeq =
1189 Vc::make_index_sequence<determine_tuple_size<typename A::scalar_type>()>;
1190
1191 public:
1192 Interface(reference aa) : a(aa) {}
1193
1194 Scalar<A> operator[](size_t i)
1195 {
1196 return {a, i};
1197 }
1198 typename A::scalar_type operator[](size_t i) const
1199 {
1200 return extract_impl(a, i, IndexSeq());
1201 }
1202
1203 A shifted(int amount) const
1204 {
1205 return shifted_impl(a, amount, IndexSeq());
1206 }
1207
1208 void load(const typename A::scalar_type *mem) { load_interleaved(*this, mem); }
1209 void store(typename A::scalar_type *mem) { store_interleaved(*this, mem); }
1210
1211 private:
1212 reference a;
1213 };
1214 }
1215
1216
1217
1218
1219
1220 template <typename S, typename T, size_t N>
1221 inline void assign(SimdizeDetail::Adapter<S, T, N> &a, size_t i, const S &x)
1222 {
1223 SimdizeDetail::assign_impl(
1224 a, i, x, Vc::make_index_sequence<SimdizeDetail::determine_tuple_size<T>()>());
1225 }
1226
1227
1228
1229 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
1230 Vc_INTRINSIC void assign(V &v, size_t i, typename V::EntryType x)
1231 {
1232 v[i] = x;
1233 }
1234
1235
1236
1237
1238
1239
1240 template <typename S, typename T, size_t N>
1241 inline S extract(const SimdizeDetail::Adapter<S, T, N> &a, size_t i)
1242 {
1243 return SimdizeDetail::extract_impl(
1244 a, i, Vc::make_index_sequence<SimdizeDetail::determine_tuple_size<S>()>());
1245 }
1246
1247
1248
1249 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
1250 Vc_INTRINSIC typename V::EntryType extract(const V &v, size_t i)
1251 {
1252 return v[i];
1253 }
1254
1255
1256 template <class S, class T, size_t N>
1257 inline void load_interleaved(SimdizeDetail::Adapter<S, T, N> &a, const S *mem)
1258 {
1259 if (SimdizeDetail::homogeneous_sizeof<S>::value == 0) {
1260 Common::unrolled_loop<std::size_t, 0, N>(
1261 [&](std::size_t i) { assign(a, i, mem[i]); });
1262 } else {
1263 constexpr size_t TupleSize = SimdizeDetail::determine_tuple_size_<S>::value;
1264 SimdizeDetail::load_interleaved_impl(Vc::make_index_sequence<TupleSize>(), a,
1265 mem);
1266 }
1267 }
1268 template <
1269 class V, class T,
1270 class = enable_if<Traits::is_simd_vector<V>::value && std::is_arithmetic<T>::value>>
1271 Vc_INTRINSIC void load_interleaved(V &a, const T *mem)
1272 {
1273 a.load(mem, Vc::Unaligned);
1274 }
1275
1276
1277 template <class S, class T, size_t N>
1278 inline void store_interleaved(const SimdizeDetail::Adapter<S, T, N> &a, S *mem)
1279 {
1280 if (SimdizeDetail::homogeneous_sizeof<S>::value == 0) {
1281 Common::unrolled_loop<std::size_t, 0, N>(
1282 [&](std::size_t i) { mem[i] = extract(a, i); });
1283 } else {
1284 constexpr size_t TupleSize = SimdizeDetail::determine_tuple_size_<S>::value;
1285 SimdizeDetail::store_interleaved_impl(Vc::make_index_sequence<TupleSize>(), a,
1286 mem);
1287 }
1288 }
1289 template <
1290 class V, class T,
1291 class = enable_if<Traits::is_simd_vector<V>::value && std::is_arithmetic<T>::value>>
1292 Vc_INTRINSIC void store_interleaved(const V &a, T *mem)
1293 {
1294 a.store(mem, Vc::Unaligned);
1295 }
1296
1297
1298 template <typename S, typename T, size_t N>
1299 SimdizeDetail::Interface<SimdizeDetail::Adapter<S, T, N>> decorate(
1300 SimdizeDetail::Adapter<S, T, N> &a)
1301 {
1302 return {a};
1303 }
1304 template <typename S, typename T, size_t N>
1305 const SimdizeDetail::Interface<const SimdizeDetail::Adapter<S, T, N>> decorate(
1306 const SimdizeDetail::Adapter<S, T, N> &a)
1307 {
1308 return {a};
1309 }
1310 template <class V, class = typename std::enable_if<
1311 Traits::is_simd_vector<typename std::decay<V>::type>::value>>
1312 V &&decorate(V &&v)
1313 {
1314 return std::forward<V>(v);
1315 }
1316
1317 namespace SimdizeDetail
1318 {
1319
1320 template <typename Scalar, typename Base, size_t N>
1321 template <class F, class>
1322 Adapter<Scalar, Base, N>::Adapter(F &&fun)
1323 {
1324 for (size_t i = 0; i < N; ++i) {
1325 Vc::assign(*this, i, fun(i));
1326 }
1327 }
1328
1329 namespace IteratorDetails
1330 {
1331 enum class Mutable { Yes, No };
1332
1333 template <typename It, typename V, size_t I, size_t End>
1334 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I == End), It>)
1335 {
1336 return {};
1337 }
1338 template <typename It, typename V, size_t I, size_t End>
1339 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I < End), It> it)
1340 {
1341 V r = fromIteratorImpl<It, V, I + 1, End>(it);
1342 Traits::decay<decltype(get_dispatcher<I>(r))> tmp;
1343 for (size_t j = 0; j < V::size(); ++j, ++it) {
1344 tmp[j] = get_dispatcher<I>(*it);
1345 }
1346 get_dispatcher<I>(r) = tmp;
1347 return r;
1348 }
1349 template <typename It, typename V>
1350 Vc_INTRINSIC V fromIterator(enable_if<!Traits::is_simd_vector<V>::value, const It &> it)
1351 {
1352 return fromIteratorImpl<It, V, 0, determine_tuple_size<V>()>(it);
1353 }
1354
1355 template <typename It, typename V>
1356 Vc_INTRINSIC V fromIterator(
1357 enable_if<
1358 Traits::is_simd_vector<V>::value && Traits::has_contiguous_storage<It>::value, It>
1359 it)
1360 {
1361 #ifndef _MSC_VER
1362
1363
1364 Vc_ASSERT(&*it + 1 == &*(it + 1));
1365 #endif
1366 return V(&*it, Vc::Unaligned);
1367 }
1368
1369 template <typename It, typename V>
1370 Vc_INTRINSIC V fromIterator(enable_if<Traits::is_simd_vector<V>::value &&
1371 !Traits::has_contiguous_storage<It>::value,
1372 It>
1373 it)
1374 {
1375 V r;
1376 for (size_t j = 0; j < V::size(); ++j, ++it) {
1377 r[j] = *it;
1378 }
1379 return r;
1380 }
1381
1382
1383
1384
1385 template <typename T, typename value_vector, Mutable> class Pointer;
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395 template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::Yes>
1396 {
1397 static constexpr auto Size = value_vector::size();
1398
1399 public:
1400
1401 value_vector *operator->() { return &data; }
1402
1403
1404
1405
1406
1407 Pointer() = delete;
1408 Pointer(const Pointer &) = delete;
1409 Pointer &operator=(const Pointer &) = delete;
1410 Pointer &operator=(Pointer &&) = delete;
1411
1412
1413 Pointer(Pointer &&) = default;
1414
1415
1416
1417
1418
1419
1420 ~Pointer()
1421 {
1422
1423 for (size_t i = 0; i < Size; ++i, ++begin_iterator) {
1424 *begin_iterator = extract(data, i);
1425 }
1426 }
1427
1428
1429 Pointer(const T &it) : data(fromIterator<T, value_vector>(it)), begin_iterator(it) {}
1430
1431 private:
1432
1433 value_vector data;
1434
1435 T begin_iterator;
1436 };
1437
1438
1439
1440
1441
1442 template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::No>
1443 {
1444 static constexpr auto Size = value_vector::size();
1445
1446 public:
1447 const value_vector *operator->() const { return &data; }
1448
1449 Pointer() = delete;
1450 Pointer(const Pointer &) = delete;
1451 Pointer &operator=(const Pointer &) = delete;
1452 Pointer &operator=(Pointer &&) = delete;
1453
1454 Pointer(Pointer &&) = default;
1455
1456 Pointer(const T &it) : data(fromIterator<T, value_vector>(it)) {}
1457
1458 private:
1459 value_vector data;
1460 };
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474 template <typename T, typename value_vector, Mutable M> class Reference;
1475
1476
1477 template <typename T, typename value_vector>
1478 class Reference<T, value_vector, Mutable::Yes> : public value_vector
1479 {
1480 static constexpr auto Size = value_vector::size();
1481
1482 using reference = typename std::add_lvalue_reference<T>::type;
1483 reference scalar_it;
1484
1485 public:
1486
1487
1488 Reference(reference first_it)
1489 : value_vector(fromIterator<T, value_vector>(first_it)), scalar_it(first_it)
1490 {
1491 }
1492
1493
1494 Reference(const Reference &) = delete;
1495 Reference(Reference &&) = default;
1496 Reference &operator=(const Reference &) = delete;
1497 Reference &operator=(Reference &&) = delete;
1498
1499
1500
1501
1502
1503
1504 void operator=(const value_vector &x)
1505 {
1506 static_cast<value_vector &>(*this) = x;
1507 auto it = scalar_it;
1508 for (size_t i = 0; i < Size; ++i, ++it) {
1509 *it = extract(x, i);
1510 }
1511 }
1512 };
1513 #define Vc_OP(op_) \
1514 template <typename T0, typename V0, typename T1, typename V1> \
1515 decltype(std::declval<const V0 &>() op_ std::declval<const V1 &>()) operator op_( \
1516 const Reference<T0, V0, Mutable::Yes> &x, \
1517 const Reference<T1, V1, Mutable::Yes> &y) \
1518 { \
1519 return static_cast<const V0 &>(x) op_ static_cast<const V1 &>(y); \
1520 }
1521 Vc_ALL_COMPARES(Vc_OP);
1522 Vc_ALL_ARITHMETICS(Vc_OP);
1523 Vc_ALL_BINARY(Vc_OP);
1524 Vc_ALL_LOGICAL(Vc_OP);
1525 Vc_ALL_SHIFTS(Vc_OP);
1526 #undef Vc_OP
1527
1528
1529 template <typename T, typename value_vector>
1530 class Reference<T, value_vector, Mutable::No> : public value_vector
1531 {
1532 static constexpr auto Size = value_vector::size();
1533
1534 public:
1535 Reference(const T &it) : value_vector(fromIterator<T, value_vector>(it)) {}
1536
1537 Reference(const Reference &) = delete;
1538 Reference(Reference &&) = default;
1539 Reference &operator=(const Reference &) = delete;
1540 Reference &operator=(Reference &&) = delete;
1541
1542
1543 void operator=(const value_vector &x) = delete;
1544 };
1545
1546 template <typename T, size_t N,
1547 IteratorDetails::Mutable M =
1548 (Traits::is_output_iterator<T>::value ? Mutable::Yes : Mutable::No),
1549 typename V = simdize<typename std::iterator_traits<T>::value_type, N>,
1550 size_t Size = V::Size,
1551 typename = typename std::iterator_traits<T>::iterator_category>
1552 class Iterator;
1553
1554 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size_>
1555 class Iterator<T, N, M, V, Size_, std::forward_iterator_tag>
1556 {
1557 public:
1558 using iterator_category = typename std::iterator_traits<T>::iterator_category;
1559 using difference_type = typename std::iterator_traits<T>::difference_type;
1560 using value_type = V;
1561 using pointer = IteratorDetails::Pointer<T, V, M>;
1562 using reference = IteratorDetails::Reference<T, V, M>;
1563 using const_pointer = IteratorDetails::Pointer<T, V, IteratorDetails::Mutable::No>;
1564 using const_reference =
1565 IteratorDetails::Reference<T, V, IteratorDetails::Mutable::No>;
1566
1567
1568 static constexpr std::size_t size() { return Size_; }
1569 static constexpr std::size_t Size = Size_;
1570
1571 Iterator() = default;
1572
1573
1574
1575
1576
1577
1578
1579 Iterator(const T &x) : scalar_it(x) {}
1580
1581
1582
1583 Iterator(T &&x) : scalar_it(std::move(x)) {}
1584
1585
1586
1587 Iterator &operator=(const T &x)
1588 {
1589 scalar_it = x;
1590 return *this;
1591 }
1592
1593
1594
1595 Iterator &operator=(T &&x)
1596 {
1597 scalar_it = std::move(x);
1598 return *this;
1599 }
1600
1601
1602 Iterator(const Iterator &) = default;
1603
1604 Iterator(Iterator &&) = default;
1605
1606 Iterator &operator=(const Iterator &) = default;
1607
1608 Iterator &operator=(Iterator &&) = default;
1609
1610
1611 Iterator &operator++()
1612 {
1613 std::advance(scalar_it, Size);
1614 return *this;
1615 }
1616
1617 Iterator operator++(int)
1618 {
1619 Iterator copy(*this);
1620 operator++();
1621 return copy;
1622 }
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632 bool operator==(const Iterator &rhs) const
1633 {
1634 #ifndef NDEBUG
1635 if (scalar_it == rhs.scalar_it) {
1636 return true;
1637 } else {
1638 T it(scalar_it);
1639 for (size_t i = 1; i < Size; ++i) {
1640 Vc_ASSERT((++it != rhs.scalar_it));
1641 }
1642 return false;
1643 }
1644 #else
1645 return scalar_it == rhs.scalar_it;
1646 #endif
1647 }
1648
1649
1650
1651
1652
1653
1654
1655
1656 bool operator!=(const Iterator &rhs) const
1657 {
1658 return !operator==(rhs);
1659 }
1660
1661 pointer operator->() { return scalar_it; }
1662
1663
1664
1665
1666
1667
1668
1669 reference operator*() { return scalar_it; }
1670
1671 const_pointer operator->() const { return scalar_it; }
1672
1673
1674
1675
1676
1677
1678
1679
1680 const_reference operator*() const { return scalar_it; }
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695 operator const T &() const { return scalar_it; }
1696
1697 protected:
1698 T scalar_it;
1699 };
1700
1701
1702
1703
1704
1705 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1706 class Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1707 : public Iterator<T, N, M, V, Size, std::forward_iterator_tag>
1708 {
1709 using Base = Iterator<T, N, M, V, Size, std::forward_iterator_tag>;
1710
1711 protected:
1712 using Base::scalar_it;
1713
1714 public:
1715 using pointer = typename Base::pointer;
1716 using reference = typename Base::reference;
1717 using const_pointer = typename Base::const_pointer;
1718 using const_reference = typename Base::const_reference;
1719
1720 using Iterator<T, N, M, V, Size,
1721 std::forward_iterator_tag>::Iterator;
1722
1723
1724
1725 Iterator &operator--()
1726 {
1727 std::advance(scalar_it, -Size);
1728 return *this;
1729 }
1730
1731 Iterator operator--(int)
1732 {
1733 Iterator copy(*this);
1734 operator--();
1735 return copy;
1736 }
1737 };
1738
1739
1740
1741
1742
1743 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1744 class Iterator<T, N, M, V, Size, std::random_access_iterator_tag>
1745 : public Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1746 {
1747 using Base = Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>;
1748
1749 protected:
1750 using Base::scalar_it;
1751
1752 public:
1753 using pointer = typename Base::pointer;
1754 using reference = typename Base::reference;
1755 using const_pointer = typename Base::const_pointer;
1756 using const_reference = typename Base::const_reference;
1757 using difference_type = typename std::iterator_traits<T>::difference_type;
1758
1759 using Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>::
1760 Iterator;
1761
1762 Iterator &operator+=(difference_type n)
1763 {
1764 scalar_it += n * difference_type(Size);
1765 return *this;
1766 }
1767 Iterator operator+(difference_type n) const { return Iterator(*this) += n; }
1768
1769 Iterator &operator-=(difference_type n)
1770 {
1771 scalar_it -= n * difference_type(Size);
1772 return *this;
1773 }
1774 Iterator operator-(difference_type n) const { return Iterator(*this) -= n; }
1775
1776 difference_type operator-(const Iterator &rhs) const
1777 {
1778 constexpr difference_type n = Size;
1779 Vc_ASSERT((scalar_it - rhs.scalar_it) % n ==
1780 0);
1781
1782
1783
1784
1785 return (scalar_it - rhs.scalar_it) / n;
1786 }
1787
1788
1789
1790
1791
1792 bool operator<(const Iterator &rhs) const
1793 {
1794 return rhs.scalar_it - scalar_it >= difference_type(Size);
1795 }
1796
1797 bool operator>(const Iterator &rhs) const
1798 {
1799 return scalar_it - rhs.scalar_it >= difference_type(Size);
1800 }
1801
1802 bool operator<=(const Iterator &rhs) const
1803 {
1804 return rhs.scalar_it - scalar_it >= difference_type(Size) - 1;
1805 }
1806
1807 bool operator>=(const Iterator &rhs) const
1808 {
1809 return scalar_it - rhs.scalar_it >= difference_type(Size) - 1;
1810 }
1811
1812 reference operator[](difference_type i) { return *(*this + i); }
1813 const_reference operator[](difference_type i) const { return *(*this + i); }
1814 };
1815
1816 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1817 Iterator<T, N, M, V, Size, std::random_access_iterator_tag> operator+(
1818 typename Iterator<T, N, M, V, Size, std::random_access_iterator_tag>::difference_type
1819 n,
1820 const Iterator<T, N, M, V, Size, std::random_access_iterator_tag> &i)
1821 {
1822 return i + n;
1823 }
1824
1825 }
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835 template <typename T, size_t N, typename MT>
1836 struct ReplaceTypes<T, N, MT, Category::ForwardIterator>
1837 {
1838 using type = IteratorDetails::Iterator<T, N>;
1839 };
1840 template <typename T, size_t N, typename MT>
1841 struct ReplaceTypes<T, N, MT, Category::BidirectionalIterator>
1842 {
1843 using type = IteratorDetails::Iterator<T, N>;
1844 };
1845 template <typename T, size_t N, typename MT>
1846 struct ReplaceTypes<T, N, MT, Category::RandomAccessIterator>
1847 {
1848 using type = IteratorDetails::Iterator<T, N>;
1849 };
1850
1851
1852
1853
1854 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1855 std::size_t Offset>
1856 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size_<S>::value && M::Size == N), void>
1857 conditional_assign(Adapter<S, T, N> &, const M &, const U &)
1858 {
1859 }
1860 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1861 std::size_t Offset = 0>
1862 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size_<S>::value && M::Size == N), void>
1863 conditional_assign(Adapter<S, T, N> &lhs, const M &mask, const U &rhs)
1864 {
1865 using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1866 using M2 = typename V::mask_type;
1867 conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask), get_dispatcher<Offset>(rhs));
1868 conditional_assign<Op, S, T, N, M, U, Offset + 1>(lhs, mask, rhs);
1869 }
1870 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1871 std::size_t Offset>
1872 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size_<S>::value && M::Size == N), void>
1873 conditional_assign(Adapter<S, T, N> &, const M &)
1874 {
1875 }
1876 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1877 std::size_t Offset = 0>
1878 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size_<S>::value && M::Size == N), void>
1879 conditional_assign(Adapter<S, T, N> &lhs, const M &mask)
1880 {
1881 using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1882 using M2 = typename V::mask_type;
1883 conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask));
1884 conditional_assign<Op, S, T, N, M, Offset + 1>(lhs, mask);
1885 }
1886
1887
1888 }
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909 template <typename T, size_t N = 0, typename MT = void>
1910 using simdize = SimdizeDetail::simdize<T, N, MT>;
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931 #define Vc_SIMDIZE_INTERFACE(MEMBERS_) \
1932 template <std::size_t N_> \
1933 inline auto vc_get_()->decltype(std::get<N_>(std::tie MEMBERS_)) \
1934 { \
1935 return std::get<N_>(std::tie MEMBERS_); \
1936 } \
1937 template <std::size_t N_> \
1938 inline auto vc_get_() const->decltype(std::get<N_>(std::tie MEMBERS_)) \
1939 { \
1940 return std::get<N_>(std::tie MEMBERS_); \
1941 } \
1942 enum : std::size_t { \
1943 tuple_size = std::tuple_size<decltype(std::make_tuple MEMBERS_)>::value \
1944 }
1945
1946 }
1947
1948 namespace std
1949 {
1950 using Vc::SimdizeDetail::swap;
1951 }
1952
1953 #endif
1954
1955