29 #ifndef VC_COMMON_SIMDIZE_H_
30 #define VC_COMMON_SIMDIZE_H_
96 namespace Vc_VERSIONED_NAMESPACE
104 namespace SimdizeDetail
111 using std::is_base_of;
112 using std::false_type;
113 using std::true_type;
114 using std::iterator_traits;
115 using std::conditional;
117 template <
bool B,
typename T,
typename F>
118 using conditional_t =
typename conditional<B, T, F>::type;
124 template <
typename... Ts>
struct Typelist;
129 enum class Category {
133 ArithmeticVectorizable,
141 BidirectionalIterator,
143 RandomAccessIterator,
152 template <
typename T,
153 typename ItCat =
typename iterator_traits<T>::iterator_category>
154 constexpr Category iteratorCategories(
int)
156 return is_base_of<std::random_access_iterator_tag, ItCat>::value
157 ? Category::RandomAccessIterator
158 : is_base_of<std::bidirectional_iterator_tag, ItCat>::value
159 ? Category::BidirectionalIterator
160 : is_base_of<std::forward_iterator_tag, ItCat>::value
161 ? Category::ForwardIterator
162 : is_base_of<std::output_iterator_tag, ItCat>::value
163 ? Category::OutputIterator
164 : is_base_of<std::input_iterator_tag, ItCat>::value
165 ? Category::InputIterator
171 template <
typename T> constexpr Category iteratorCategories(...)
173 return Category::None;
179 template <
typename T>
struct is_class_template :
public false_type
182 template <
template <
typename...>
class C,
typename... Ts>
183 struct is_class_template<C<Ts...>> :
public true_type
190 template <
typename T> constexpr Category typeCategory()
192 return (is_same<T, bool>::value || is_same<T, short>::value ||
193 is_same<T, unsigned short>::value || is_same<T, int>::value ||
194 is_same<T, unsigned int>::value || is_same<T, float>::value ||
195 is_same<T, double>::value)
196 ? Category::ArithmeticVectorizable
197 : iteratorCategories<T>(int()) != Category::None
198 ? iteratorCategories<T>(
int())
199 : is_class_template<T>::value ? Category::ClassTemplate
208 template <typename T, size_t TupleSize = std::tuple_size<T>::value>
209 constexpr
size_t determine_tuple_size()
213 template <
typename T,
size_t TupleSize = T::tuple_size>
214 constexpr
size_t determine_tuple_size(
size_t = T::tuple_size)
221 template <
typename T>
struct The_simdization_for_the_requested_type_is_not_implemented;
236 template <
typename T,
size_t N,
typename MT, Category = typeCategory<T>()>
237 struct ReplaceTypes :
public The_simdization_for_the_requested_type_is_not_implemented<T>
245 template <
typename T,
size_t N,
typename MT>
struct ReplaceTypes<T, N, MT, Category::None>
254 template <
typename T,
size_t N = 0,
typename MT =
void>
255 using simdize =
typename SimdizeDetail::ReplaceTypes<T, N, MT>::type;
261 template <
typename T,
size_t N,
typename MT>
262 struct ReplaceTypes<T, N, MT, Category::ArithmeticVectorizable>
263 :
public conditional<(N == 0 || Vector<T>::size() == N), Vector<T>, SimdArray<T, N>>
271 template <
size_t N,
typename MT>
272 struct ReplaceTypes<bool, N, MT, Category::ArithmeticVectorizable>
273 :
public conditional<(N == 0 || Mask<MT>::size() == N), Mask<MT>,
274 SimdMaskArray<MT, N>>
281 struct ReplaceTypes<bool, N, void, Category::ArithmeticVectorizable>
282 :
public ReplaceTypes<bool, N, float, Category::ArithmeticVectorizable>
292 template <
size_t N,
typename MT,
typename Replaced,
typename... Remaining>
293 struct SubstituteOneByOne;
299 template <
size_t N,
typename MT,
typename... Replaced,
typename T,
300 typename... Remaining>
301 struct SubstituteOneByOne<N, MT, Typelist<Replaced...>, T, Remaining...>
308 template <
typename U,
size_t M = U::size()>
309 static std::integral_constant<size_t, M> size_or_0(
int);
310 template <
typename U>
static std::integral_constant<size_t, 0> size_or_0(...);
313 using V = simdize<T, N, MT>;
319 static constexpr
auto NewN = N != 0 ? N : decltype(size_or_0<V>(
int()))::value;
326 typedef conditional_t<(N != NewN && is_same<MT, void>::value),
327 conditional_t<is_same<T, bool>::value,
float, T>, MT> NewMT;
333 using type =
typename SubstituteOneByOne<NewN, NewMT, Typelist<Replaced..., V>,
339 template <
size_t Size,
typename... Replaced>
struct SubstitutedBase;
341 template <
typename Replaced>
struct SubstitutedBase<1, Replaced> {
342 template <
typename ValueT,
template <
typename, ValueT...>
class C, ValueT... Values>
343 using SubstitutedWithValues = C<Replaced, Values...>;
346 template <
typename R0,
typename R1>
struct SubstitutedBase<2, R0, R1>
348 template <
typename ValueT,
template <
typename,
typename, ValueT...>
class C,
350 using SubstitutedWithValues = C<R0, R1, Values...>;
353 template <
typename R0,
typename R1,
typename R2>
struct SubstitutedBase<3, R0, R1, R2>
355 template <
typename ValueT,
template <
typename,
typename,
typename, ValueT...>
class C,
357 using SubstitutedWithValues = C<R0, R1, R2, Values...>;
360 template <
typename... Replaced>
struct SubstitutedBase<4, Replaced...> {
362 template <
typename ValueT,
363 template <
typename,
typename,
typename,
typename, ValueT...>
class C,
365 using SubstitutedWithValues = C<Replaced..., Values...>;
369 template <
typename... Replaced>
struct SubstitutedBase<5, Replaced...> {
371 template <
typename ValueT,
template <
typename,
typename,
typename,
typename,
typename,
374 using SubstitutedWithValues = C<Replaced..., Values...>;
378 template <
typename... Replaced>
struct SubstitutedBase<6, Replaced...> {
380 template <
typename ValueT,
template <
typename,
typename,
typename,
typename,
typename,
381 typename, ValueT...>
class C,
383 using SubstitutedWithValues = C<Replaced..., Values...>;
387 template <
typename... Replaced>
struct SubstitutedBase<7, Replaced...> {
389 template <
typename ValueT,
template <
typename,
typename,
typename,
typename,
typename,
390 typename,
typename, ValueT...>
class C,
392 using SubstitutedWithValues = C<Replaced..., Values...>;
396 template <
typename... Replaced>
struct SubstitutedBase<8, Replaced...> {
398 template <
typename ValueT,
template <
typename,
typename,
typename,
typename,
typename,
399 typename,
typename,
typename, ValueT...>
class C,
401 using SubstitutedWithValues = C<Replaced..., Values...>;
410 template <
size_t N_,
typename MT,
typename Replaced0,
typename... Replaced>
411 struct SubstituteOneByOne<N_, MT, Typelist<Replaced0, Replaced...>>
417 :
public SubstitutedBase<sizeof...(Replaced) + 1, Replaced0, Replaced...> {
418 static constexpr
auto N = N_;
423 template <
template <
typename...>
class C>
424 using Substituted = C<Replaced0, Replaced...>;
444 template <
typename Scalar,
typename Base,
size_t N>
class Adapter;
450 template <
template <
typename...>
class C,
typename... Ts,
size_t N,
typename MT>
451 struct ReplaceTypes<C<Ts...>, N, MT, Category::ClassTemplate>
454 using SubstitutionResult =
455 typename SubstituteOneByOne<N, MT, Typelist<>, Ts...>::type;
461 using Vectorized =
typename SubstitutionResult::template Substituted<C>;
467 using type = conditional_t<is_same<C<Ts...>, Vectorized>::value, C<Ts...>,
468 Adapter<C<Ts...>, Vectorized, SubstitutionResult::N>>;
478 #define Vc_DEFINE_NONTYPE_REPLACETYPES__(ValueType__) \
479 template <template <typename, ValueType__...> class C, typename T, \
480 ValueType__ Value0, ValueType__... Values> \
481 struct is_class_template<C<T, Value0, Values...>> : public true_type \
484 template <template <typename, typename, ValueType__...> class C, typename T0, \
485 typename T1, ValueType__ Value0, ValueType__... Values> \
486 struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type \
489 template <template <typename, typename, typename, ValueType__...> class C, \
490 typename T0, typename T1, typename T2, ValueType__ Value0, \
491 ValueType__... Values> \
492 struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type \
495 template <template <typename, typename, typename, typename, ValueType__...> class C, \
496 typename T0, typename T1, typename T2, typename T3, ValueType__ Value0, \
497 ValueType__... Values> \
498 struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type \
502 template <typename, typename, typename, typename, typename, ValueType__...> \
503 class C, typename T0, typename T1, typename T2, typename T3, typename T4, \
504 ValueType__ Value0, ValueType__... Values> \
505 struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
509 template <template <typename, typename, typename, typename, typename, typename, \
510 ValueType__...> class C, \
511 typename T0, typename T1, typename T2, typename T3, typename T4, \
512 typename T5, ValueType__ Value0, ValueType__... Values> \
513 struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
517 template <template <typename, typename, typename, typename, typename, typename, \
518 typename, ValueType__...> class C, \
519 typename T0, typename T1, typename T2, typename T3, typename T4, \
520 typename T5, typename T6, ValueType__ Value0, ValueType__... Values> \
521 struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
525 template <template <typename, ValueType__> class C, typename T0, ValueType__ Value0, \
526 size_t N, typename MT> \
527 struct ReplaceTypes<C<T0, Value0>, N, MT, Category::ClassTemplate> \
529 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
530 typedef typename tmp::template SubstitutedWithValues<ValueType__, C, Value0> \
532 static constexpr auto NN = tmp::N; \
533 typedef conditional_t<is_same<C<T0, Value0>, Substituted>::value, C<T0, Value0>, \
534 Adapter<C<T0, Value0>, Substituted, NN>> type; \
536 template <template <typename, typename, ValueType__> class C, typename T0, \
537 typename T1, ValueType__ Value0, size_t N, typename MT> \
538 struct ReplaceTypes<C<T0, T1, Value0>, N, MT, Category::ClassTemplate> \
540 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
541 typedef typename tmp::template SubstitutedWithValues<ValueType__, C, Value0> \
543 static constexpr auto NN = tmp::N; \
544 typedef conditional_t<is_same<C<T0, T1, Value0>, Substituted>::value, \
546 Adapter<C<T0, T1, Value0>, Substituted, NN>> type; \
548 template <template <typename, typename, typename, ValueType__> class C, typename T0, \
549 typename T1, typename T2, ValueType__ Value0, size_t N, typename MT> \
550 struct ReplaceTypes<C<T0, T1, T2, Value0>, N, MT, Category::ClassTemplate> \
552 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
553 typedef typename tmp::template SubstitutedWithValues<ValueType__, C, Value0> \
555 static constexpr auto NN = tmp::N; \
556 typedef conditional_t<is_same<C<T0, T1, T2, Value0>, Substituted>::value, \
557 C<T0, T1, T2, Value0>, \
558 Adapter<C<T0, T1, T2, Value0>, Substituted, NN>> type; \
561 #define Vc_DEFINE_NONTYPE_REPLACETYPES__(ValueType__) \
562 template <template <typename, ValueType__...> class C, typename T, \
563 ValueType__ Value0, ValueType__... Values> \
564 struct is_class_template<C<T, Value0, Values...>> : public true_type { \
566 template <template <typename, typename, ValueType__...> class C, typename T0, \
567 typename T1, ValueType__ Value0, ValueType__... Values> \
568 struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type { \
570 template <template <typename, typename, typename, ValueType__...> class C, \
571 typename T0, typename T1, typename T2, ValueType__ Value0, \
572 ValueType__... Values> \
573 struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type { \
575 template <template <typename, typename, typename, typename, ValueType__...> class C, \
576 typename T0, typename T1, typename T2, typename T3, ValueType__ Value0, \
577 ValueType__... Values> \
578 struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type { \
580 template <template <typename, typename, typename, typename, typename, \
581 ValueType__...> class C, \
582 typename T0, typename T1, typename T2, typename T3, typename T4, \
583 ValueType__ Value0, ValueType__... Values> \
584 struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
585 : public true_type { \
587 template <template <typename, typename, typename, typename, typename, typename, \
588 ValueType__...> class C, \
589 typename T0, typename T1, typename T2, typename T3, typename T4, \
590 typename T5, ValueType__ Value0, ValueType__... Values> \
591 struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
592 : public true_type { \
594 template <template <typename, typename, typename, typename, typename, typename, \
595 typename, ValueType__...> class C, \
596 typename T0, typename T1, typename T2, typename T3, typename T4, \
597 typename T5, typename T6, ValueType__ Value0, ValueType__... Values> \
598 struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
599 : public true_type { \
601 template <template <typename, ValueType__...> class C, typename T0, \
602 ValueType__ Value0, ValueType__... Values, size_t N, typename MT> \
603 struct ReplaceTypes<C<T0, Value0, Values...>, N, MT, Category::ClassTemplate> { \
604 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
605 typedef typename tmp::template SubstitutedWithValues<ValueType__, C, Value0, \
606 Values...> Substituted; \
607 static constexpr auto NN = tmp::N; \
608 typedef conditional_t<is_same<C<T0, Value0, Values...>, Substituted>::value, \
609 C<T0, Value0, Values...>, \
610 Adapter<C<T0, Value0, Values...>, Substituted, NN>> type; \
612 template <template <typename, typename, ValueType__...> class C, typename T0, \
613 typename T1, ValueType__ Value0, ValueType__... Values, size_t N, \
615 struct ReplaceTypes<C<T0, T1, Value0, Values...>, N, MT, Category::ClassTemplate> { \
616 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
617 typedef typename tmp::template SubstitutedWithValues<ValueType__, C, Value0, \
618 Values...> Substituted; \
619 static constexpr auto NN = tmp::N; \
620 typedef conditional_t<is_same<C<T0, T1, Value0, Values...>, Substituted>::value, \
621 C<T0, T1, Value0, Values...>, \
622 Adapter<C<T0, T1, Value0, Values...>, Substituted, NN>> \
625 template <template <typename, typename, typename, ValueType__...> class C, \
626 typename T0, typename T1, typename T2, ValueType__ Value0, \
627 ValueType__... Values, size_t N, typename MT> \
628 struct ReplaceTypes<C<T0, T1, T2, Value0, Values...>, N, MT, \
629 Category::ClassTemplate> { \
630 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
631 typedef typename tmp::template SubstitutedWithValues<ValueType__, C, Value0, \
632 Values...> Substituted; \
633 static constexpr auto NN = tmp::N; \
634 typedef conditional_t< \
635 is_same<C<T0, T1, T2, Value0, Values...>, Substituted>::value, \
636 C<T0, T1, T2, Value0, Values...>, \
637 Adapter<C<T0, T1, T2, Value0, Values...>, Substituted, NN>> type; \
640 Vc_DEFINE_NONTYPE_REPLACETYPES__(
bool);
641 Vc_DEFINE_NONTYPE_REPLACETYPES__(
wchar_t);
642 Vc_DEFINE_NONTYPE_REPLACETYPES__(
char);
643 Vc_DEFINE_NONTYPE_REPLACETYPES__(
signed char);
644 Vc_DEFINE_NONTYPE_REPLACETYPES__(
unsigned char);
645 Vc_DEFINE_NONTYPE_REPLACETYPES__(
signed short);
646 Vc_DEFINE_NONTYPE_REPLACETYPES__(
unsigned short);
647 Vc_DEFINE_NONTYPE_REPLACETYPES__(
signed int);
648 Vc_DEFINE_NONTYPE_REPLACETYPES__(
unsigned int);
649 Vc_DEFINE_NONTYPE_REPLACETYPES__(
signed long);
650 Vc_DEFINE_NONTYPE_REPLACETYPES__(
unsigned long);
651 Vc_DEFINE_NONTYPE_REPLACETYPES__(
signed long long);
652 Vc_DEFINE_NONTYPE_REPLACETYPES__(
unsigned long long);
653 #undef Vc_DEFINE_NONTYPE_REPLACETYPES__
657 template <
typename Class,
typename... Args>
658 constexpr
bool is_constructible_with_single_brace()
662 template <
typename Class,
typename... Args>
663 constexpr
bool is_constructible_with_double_brace()
668 namespace is_constructible_with_single_brace_impl
670 template <
typename T> T create();
671 template <
typename Class,
typename... Args,
672 typename = decltype((Class{create<Args>()...}))>
673 std::true_type test(
int);
674 template <
typename Class,
typename... Args> std::false_type test(...);
677 template <
typename Class,
typename... Args>
678 constexpr
bool is_constructible_with_single_brace()
681 is_constructible_with_single_brace_impl::test<Class, Args...>(1))::value;
684 is_constructible_with_single_brace<std::tuple<int, int, int>,
int,
int,
int>(),
"");
685 static_assert(is_constructible_with_single_brace<std::array<int, 3>,
int,
int,
int>(),
688 namespace is_constructible_with_double_brace_impl
690 template <
typename T> T create();
691 template <
typename Class,
typename... Args,
692 typename = decltype(Class{{create<Args>()...}})>
693 std::true_type test(
int);
694 template <
typename Class,
typename... Args> std::false_type test(...);
697 template <
typename Class,
typename... Args>
698 constexpr
bool is_constructible_with_double_brace()
701 is_constructible_with_double_brace_impl::test<Class, Args...>(1))::value;
704 !is_constructible_with_double_brace<std::tuple<int, int, int>,
int,
int,
int>(),
"");
705 static_assert(is_constructible_with_double_brace<std::array<int, 3>,
int,
int,
int>(),
709 template <
size_t I,
typename T,
710 typename R = decltype(std::declval<T &>().
template vc_get__<I>())>
711 R get_dispatcher(T &x,
void * =
nullptr)
713 return x.template vc_get__<I>();
715 template <
size_t I,
typename T,
716 typename R = decltype(std::declval<const T &>().
template vc_get__<I>())>
717 R get_dispatcher(
const T &x,
void * =
nullptr)
719 return x.template vc_get__<I>();
721 template <
size_t I,
typename T,
typename R = decltype(std::get<I>(std::declval<T &>()))>
722 R get_dispatcher(T &x,
int = 0)
724 return std::get<I>(x);
726 template <
size_t I,
typename T,
727 typename R = decltype(std::get<I>(std::declval<const T &>()))>
728 R get_dispatcher(
const T &x,
int = 0)
730 return std::get<I>(x);
735 template <
typename Scalar,
typename Base,
size_t N>
class Adapter :
public Base
739 template <std::size_t... Indexes,
typename T>
740 Adapter(Vc::index_sequence<Indexes...>,
const Scalar &x__, T, std::true_type)
741 : Base{{get_dispatcher<Indexes>(x__)...}}
746 template <std::size_t... Indexes>
747 Adapter(Vc::index_sequence<Indexes...>,
const Scalar &x__, std::true_type,
749 : Base{get_dispatcher<Indexes>(x__)...}
754 template <std::size_t... Indexes>
755 Adapter(Vc::index_sequence<Indexes...>,
const Scalar &x__, std::false_type,
757 : Base(get_dispatcher<Indexes>(x__)...)
761 template <std::size_t... Indexes>
762 Adapter(Vc::index_sequence<Indexes...> seq__,
const Scalar &x__)
765 std::integral_constant<bool, is_constructible_with_single_brace<
766 Base, decltype(get_dispatcher<Indexes>(
std::declval<
767 const Scalar &>()))...>()>(),
768 std::integral_constant<bool, is_constructible_with_double_brace<
769 Base, decltype(get_dispatcher<Indexes>(
std::declval<
770 const Scalar &>()))...>()>())
776 static constexpr
size_t size() {
return N; }
779 using base_type = Base;
782 using scalar_type = Scalar;
789 #if defined Vc_CLANG && Vc_CLANG < 0x30700
790 Vc_INTRINSIC Adapter(
const Adapter &x) : Base(x) {}
792 Adapter(
const Adapter &) =
default;
794 Adapter(Adapter &&) =
default;
797 Adapter &operator=(
const Adapter &) =
default;
799 Adapter &operator=(Adapter &&) =
default;
802 template <
typename U,
size_t TupleSize = determine_tuple_size<Scalar>(),
803 typename Seq = Vc::make_index_sequence<TupleSize>,
804 typename = enable_if<std::is_convertible<U, Scalar>::value>>
806 : Adapter(Seq(), static_cast<const Scalar &>(x__))
811 template <
typename A0,
typename... Args,
812 typename =
typename std::enable_if<
813 !Traits::is_index_sequence<A0>::value &&
814 (
sizeof...(Args) > 0 || !std::is_convertible<A0, Scalar>::value)>::type>
815 Adapter(A0 &&arg0__, Args &&... arguments__)
816 : Base(
std::forward<A0>(arg0__),
std::forward<Args>(arguments__)...)
821 template <
typename T,
822 typename = decltype(Base(std::declval<
const std::initializer_list<T> &>()))>
823 Adapter(
const std::initializer_list<T> &l__)
830 void *
operator new(
size_t size) {
return Vc::Common::aligned_malloc<alignof(Adapter)>(size); }
831 void *
operator new(size_t,
void *p__) {
return p__; }
832 void *
operator new[](
size_t size) {
return Vc::Common::aligned_malloc<alignof(Adapter)>(size); }
833 void *
operator new[](size_t ,
void *p__) {
return p__; }
835 void operator delete(
void *,
void *) {}
837 void operator delete[](
void *,
void *) {}
844 template <
class... TTypes,
class... TTypesV,
class... UTypes,
class... UTypesV,
size_t N>
845 inline bool operator==(
846 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
847 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) =
delete;
848 template <
class... TTypes,
class... TTypesV,
class... UTypes,
class... UTypesV,
size_t N>
849 inline bool operator!=(
850 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
851 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) =
delete;
852 template <
class... TTypes,
class... TTypesV,
class... UTypes,
class... UTypesV,
size_t N>
853 inline bool operator<=(
854 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
855 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) =
delete;
856 template <
class... TTypes,
class... TTypesV,
class... UTypes,
class... UTypesV,
size_t N>
857 inline bool operator>=(
858 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
859 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) =
delete;
860 template <
class... TTypes,
class... TTypesV,
class... UTypes,
class... UTypesV,
size_t N>
861 inline bool operator<(
862 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
863 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) =
delete;
864 template <
class... TTypes,
class... TTypesV,
class... UTypes,
class... UTypesV,
size_t N>
865 inline bool operator>(
866 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
867 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) =
delete;
878 template <
typename Scalar,
typename Base,
size_t N>
879 class tuple_size<
Vc::SimdizeDetail::Adapter<Scalar, Base, N>> :
public tuple_size<Base>
885 template <
size_t I,
typename Scalar,
typename Base,
size_t N>
886 class tuple_element<I,
Vc::SimdizeDetail::Adapter<Scalar, Base, N>>
887 :
public tuple_element<I, Base>
897 template <
typename S,
typename T,
size_t N>
898 class allocator<
Vc::SimdizeDetail::Adapter<S, T, N>>
902 template <
typename U>
struct rebind
904 typedef std::allocator<U> other;
909 namespace Vc_VERSIONED_NAMESPACE
911 namespace SimdizeDetail
921 template <
typename T>
static inline T decay_workaround(
const T &x) {
return x; }
926 template <
typename S,
typename T,
size_t N,
size_t... Indexes>
927 inline void assign_impl(Adapter<S, T, N> &a,
size_t i,
const S &x,
928 Vc::index_sequence<Indexes...>)
930 const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(x)))...> tmp(
931 decay_workaround(get_dispatcher<Indexes>(x))...);
932 auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(tmp), 0)...};
933 if (&unused == &unused) {}
940 template <
typename S,
typename T,
size_t N>
941 inline void assign(Adapter<S, T, N> &a,
size_t i,
const S &x)
943 assign_impl(a, i, x, Vc::make_index_sequence<determine_tuple_size<T>()>());
948 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
949 Vc_INTRINSIC
void assign(V &v,
size_t i,
typename V::EntryType x)
957 template <
typename S,
typename T,
size_t N,
size_t... Indexes>
958 inline S extract_impl(
const Adapter<S, T, N> &a,
size_t i, Vc::index_sequence<Indexes...>)
960 const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[i]))...> tmp(
961 decay_workaround(get_dispatcher<Indexes>(a)[i])...);
962 return S(get_dispatcher<Indexes>(tmp)...);
969 template <
typename S,
typename T,
size_t N>
970 inline S
extract(
const Adapter<S, T, N> &a,
size_t i)
972 return extract_impl(a, i, Vc::make_index_sequence<determine_tuple_size<S>()>());
977 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
978 Vc_INTRINSIC
typename V::EntryType extract(
const V &v,
size_t i)
983 template <
typename S,
typename T, std::size_t N, std::size_t... Indexes>
984 inline Adapter<S, T, N> shifted_impl(
const Adapter<S, T, N> &a,
int shift,
985 Vc::index_sequence<Indexes...>)
988 auto &&unused = {(get_dispatcher<Indexes>(r) = get_dispatcher<Indexes>(a).shifted(shift), 0)...};
989 if (&unused == &unused) {}
1001 template <
typename S,
typename T,
size_t N>
1002 inline Adapter<S, T, N>
shifted(
const Adapter<S, T, N> &a,
int shift)
1004 return shifted_impl(a, shift, Vc::make_index_sequence<determine_tuple_size<T>()>());
1010 template <
typename S,
typename T, std::size_t N, std::size_t... Indexes>
1011 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, S &x,
1012 Vc::index_sequence<Indexes...>)
1014 const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[0]))...> tmp{
1015 decay_workaround(get_dispatcher<Indexes>(a)[i])...};
1016 auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(x), 0)...};
1017 auto &&unused2 = {(get_dispatcher<Indexes>(x) = get_dispatcher<Indexes>(tmp), 0)...};
1018 if (&unused == &unused2) {}
1020 template <
typename S,
typename T, std::size_t N, std::size_t... Indexes>
1021 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b,
1022 std::size_t j, Vc::index_sequence<Indexes...>)
1024 const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[0]))...> tmp{
1025 decay_workaround(get_dispatcher<Indexes>(a)[i])...};
1026 auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(b)[j], 0)...};
1027 auto &&unused2 = {(get_dispatcher<Indexes>(b)[j] = get_dispatcher<Indexes>(tmp), 0)...};
1028 if (&unused == &unused2) {}
1035 template <
typename S,
typename T, std::
size_t N>
1036 inline void swap(Adapter<S, T, N> &a, std::size_t i, S &x)
1038 swap_impl(a, i, x, Vc::make_index_sequence<determine_tuple_size<T>()>());
1040 template <
typename S,
typename T, std::
size_t N>
1041 inline void swap(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b, std::size_t j)
1043 swap_impl(a, i, b, j, Vc::make_index_sequence<determine_tuple_size<T>()>());
1046 template <
typename A>
class Scalar
1048 using reference =
typename std::add_lvalue_reference<A>::type;
1049 using S =
typename A::scalar_type;
1050 using IndexSeq = Vc::make_index_sequence<determine_tuple_size<S>()>;
1053 Scalar(reference aa,
size_t ii) : a(aa), i(ii) {}
1056 Scalar(
const Scalar &) =
delete;
1057 Scalar(Scalar &&) =
delete;
1058 Scalar &operator=(
const Scalar &) =
delete;
1059 Scalar &operator=(Scalar &&) =
delete;
1061 void operator=(
const S &x) { assign_impl(a, i, x, IndexSeq()); }
1062 operator S()
const {
return extract_impl(a, i, IndexSeq()); }
1064 template <
typename AA>
1065 friend inline void swap(Scalar<AA> &&a,
typename AA::scalar_type &b);
1066 template <
typename AA>
1067 friend inline void swap(
typename AA::scalar_type &b, Scalar<AA> &&a);
1068 template <
typename AA>
friend inline void swap(Scalar<AA> &&a, Scalar<AA> &&b);
1077 template <
typename A>
inline void swap(Scalar<A> &&a,
typename A::scalar_type &b)
1079 swap_impl(a.a, a.i, b,
typename Scalar<A>::IndexSeq());
1083 template <
typename A>
inline void swap(
typename A::scalar_type &b, Scalar<A> &&a)
1085 swap_impl(a.a, a.i, b,
typename Scalar<A>::IndexSeq());
1088 template <
typename A>
inline void swap(Scalar<A> &&a, Scalar<A> &&b)
1090 swap_impl(a.a, a.i, b.a, b.i,
typename Scalar<A>::IndexSeq());
1093 template <
typename A>
class Interface
1095 using reference =
typename std::add_lvalue_reference<A>::type;
1097 Vc::make_index_sequence<determine_tuple_size<typename A::scalar_type>()>;
1100 Interface(reference aa) : a(aa) {}
1102 Scalar<A> operator[](
size_t i)
1106 typename A::scalar_type operator[](
size_t i)
const
1108 return extract_impl(a, i, IndexSeq());
1113 return shifted_impl(a, amount, IndexSeq());
1120 template <
typename S,
typename T,
size_t N>
1121 Interface<Adapter<S, T, N>> decorate(Adapter<S, T, N> &a)
1125 template <
typename S,
typename T,
size_t N>
1126 const Interface<const Adapter<S, T, N>> decorate(
const Adapter<S, T, N> &a)
1131 namespace IteratorDetails
1133 enum class Mutable { Yes, No };
1135 template <
typename It,
typename V,
size_t I,
size_t End>
1136 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I == End), It>)
1140 template <
typename It,
typename V,
size_t I,
size_t End>
1141 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I < End), It> it)
1143 V r = fromIteratorImpl<It, V, I + 1, End>(it);
1144 Traits::decay<decltype(get_dispatcher<I>(r))> tmp;
1145 for (
size_t j = 0; j < V::size(); ++j, ++it) {
1146 tmp[j] = get_dispatcher<I>(*it);
1148 get_dispatcher<I>(r) = tmp;
1151 template <
typename It,
typename V>
1152 Vc_INTRINSIC V fromIterator(enable_if<!Traits::is_simd_vector<V>::value,
const It &> it)
1154 return fromIteratorImpl<It, V, 0, determine_tuple_size<V>()>(it);
1156 template <
typename It,
typename V>
1157 Vc_INTRINSIC V fromIterator(enable_if<Traits::is_simd_vector<V>::value, It> it)
1160 for (
size_t j = 0; j < V::size(); ++j, ++it) {
1169 template <
typename T,
typename value_vector, Mutable>
class Pointer;
1179 template <
typename T,
typename value_vector>
class Pointer<T, value_vector, Mutable::Yes>
1181 static constexpr
auto Size = value_vector::size();
1185 value_vector *operator->() {
return &data; }
1192 Pointer(
const Pointer &) =
delete;
1193 Pointer &operator=(
const Pointer &) =
delete;
1194 Pointer &operator=(Pointer &&) =
delete;
1197 Pointer(Pointer &&) =
default;
1207 for (
size_t i = 0; i < Size; ++i, ++begin_iterator) {
1208 *begin_iterator =
extract(data, i);
1213 Pointer(
const T &it) : data(fromIterator<T, value_vector>(it)), begin_iterator(it) {}
1226 template <
typename T,
typename value_vector>
class Pointer<T, value_vector, Mutable::No>
1228 static constexpr
auto Size = value_vector::size();
1231 const value_vector *operator->()
const {
return &data; }
1234 Pointer(
const Pointer &) =
delete;
1235 Pointer &operator=(
const Pointer &) =
delete;
1236 Pointer &operator=(Pointer &&) =
delete;
1238 Pointer(Pointer &&) =
default;
1240 Pointer(
const T &it) : data(fromIterator<T, value_vector>(it)) {}
1258 template <
typename T,
typename value_vector, Mutable M>
class Reference;
1261 template <
typename T,
typename value_vector>
1262 class Reference<T, value_vector, Mutable::Yes> :
public value_vector
1264 static constexpr
auto Size = value_vector::size();
1266 using reference =
typename std::add_lvalue_reference<T>::type;
1267 reference scalar_it;
1272 Reference(reference first_it)
1273 : value_vector(fromIterator<T, value_vector>(first_it)), scalar_it(first_it)
1278 Reference(
const Reference &) =
delete;
1279 Reference(Reference &&) =
default;
1280 Reference &operator=(
const Reference &) =
delete;
1281 Reference &operator=(Reference &&) =
delete;
1288 void operator=(
const value_vector &x)
1290 static_cast<value_vector &
>(*this) = x;
1291 auto it = scalar_it;
1292 for (
size_t i = 0; i < Size; ++i, ++it) {
1299 template <
typename T,
typename value_vector>
1300 class Reference<T, value_vector, Mutable::No> :
public value_vector
1302 static constexpr
auto Size = value_vector::size();
1305 Reference(
const T &it) : value_vector(fromIterator<T, value_vector>(it)) {}
1307 Reference(
const Reference &) =
delete;
1308 Reference(Reference &&) =
default;
1309 Reference &operator=(
const Reference &) =
delete;
1310 Reference &operator=(Reference &&) =
delete;
1313 void operator=(
const value_vector &x) =
delete;
1316 template <
typename T,
size_t N,
1317 IteratorDetails::Mutable M =
1318 (Traits::is_output_iterator<T>::value ? Mutable::Yes : Mutable::No),
1319 typename V = simdize<
typename std::iterator_traits<T>::value_type, N>,
1320 size_t Size = V::size(),
1321 typename =
typename std::iterator_traits<T>::iterator_category>
1324 template <
typename T,
size_t N, IteratorDetails::Mutable M,
typename V,
size_t Size>
1325 class Iterator<T, N, M, V, Size,
std::forward_iterator_tag>
1326 :
public std::iterator<typename std::iterator_traits<T>::iterator_category, V,
1327 typename std::iterator_traits<T>::difference_type,
1328 IteratorDetails::Pointer<T, V, M>,
1329 IteratorDetails::Reference<T, V, M>>
1332 using pointer = IteratorDetails::Pointer<T, V, M>;
1333 using reference = IteratorDetails::Reference<T, V, M>;
1334 using const_pointer = IteratorDetails::Pointer<T, V, IteratorDetails::Mutable::No>;
1335 using const_reference =
1336 IteratorDetails::Reference<T, V, IteratorDetails::Mutable::No>;
1339 static constexpr std::size_t size() {
return Size; }
1341 Iterator() =
default;
1349 Iterator(
const T &x) : scalar_it(x) {}
1353 Iterator(T &&x) : scalar_it(
std::move(x)) {}
1357 Iterator &operator=(
const T &x)
1365 Iterator &operator=(T &&x)
1367 scalar_it = std::move(x);
1372 Iterator(
const Iterator &) =
default;
1374 Iterator(Iterator &&) =
default;
1376 Iterator &operator=(
const Iterator &) =
default;
1378 Iterator &operator=(Iterator &&) =
default;
1381 Iterator &operator++()
1383 std::advance(scalar_it, Size);
1387 Iterator operator++(
int)
1389 Iterator copy(*
this);
1402 bool operator==(
const Iterator &rhs)
const
1405 for (
size_t i = 1; i < Size; ++i) {
1406 Vc_ASSERT((++it != rhs.scalar_it));
1408 return scalar_it == rhs.scalar_it;
1418 bool operator!=(
const Iterator &rhs)
const
1421 for (
size_t i = 1; i < Size; ++i) {
1422 Vc_ASSERT((++it != rhs.scalar_it));
1424 return scalar_it != rhs.scalar_it;
1427 pointer operator->() {
return scalar_it; }
1435 reference operator*() {
return scalar_it; }
1437 const_pointer operator->()
const {
return scalar_it; }
1446 const_reference operator*()
const {
return scalar_it; }
1461 operator const T &()
const {
return scalar_it; }
1471 template <
typename T,
size_t N, IteratorDetails::Mutable M,
typename V,
size_t Size>
1472 class Iterator<T, N, M, V, Size,
std::bidirectional_iterator_tag>
1473 :
public Iterator<T, N, M, V, Size, std::forward_iterator_tag>
1475 using Base = Iterator<T, N, M, V, Size, std::forward_iterator_tag>;
1478 using Base::scalar_it;
1481 using pointer =
typename Base::pointer;
1482 using reference =
typename Base::reference;
1483 using const_pointer =
typename Base::const_pointer;
1484 using const_reference =
typename Base::const_reference;
1486 using Iterator<T, N, M, V, Size,
1487 std::forward_iterator_tag>::Iterator;
1493 std::advance(scalar_it, -Size);
1499 Iterator copy(*
this);
1509 template <
typename T,
size_t N, IteratorDetails::Mutable M,
typename V,
size_t Size>
1510 class Iterator<T, N, M, V, Size,
std::random_access_iterator_tag>
1511 :
public Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1516 using Base::scalar_it;
1519 using pointer =
typename Base::pointer;
1520 using reference =
typename Base::reference;
1521 using const_pointer =
typename Base::const_pointer;
1522 using const_reference =
typename Base::const_reference;
1523 using difference_type =
typename std::iterator_traits<T>::difference_type;
1528 Iterator &operator+=(difference_type n)
1530 scalar_it += n * Size;
1533 Iterator operator+(difference_type n)
const {
return Iterator(*
this) += n; }
1535 Iterator &operator-=(difference_type n)
1537 scalar_it -= n * Size;
1540 Iterator operator-(difference_type n)
const {
return Iterator(*
this) -= n; }
1542 difference_type operator-(
const Iterator &rhs)
const
1544 constexpr difference_type n = Size;
1545 Vc_ASSERT((scalar_it - rhs.scalar_it) % n ==
1551 return (scalar_it - rhs.scalar_it) / n;
1560 return scalar_it + Size <= rhs.scalar_it;
1563 bool operator>(
const Iterator &rhs)
const
1565 return scalar_it >= rhs.scalar_it + Size;
1568 bool operator<=(
const Iterator &rhs)
const
1570 return scalar_it + (Size - 1) <= rhs.scalar_it;
1573 bool operator>=(
const Iterator &rhs)
const
1575 return scalar_it >= rhs.scalar_it + (Size - 1);
1578 reference operator[](difference_type i) {
return *(*
this + i); }
1579 const_reference operator[](difference_type i)
const {
return *(*
this + i); }
1582 template <
typename T,
size_t N, IteratorDetails::Mutable M,
typename V,
size_t Size>
1583 Iterator<T, N, M, V, Size, std::random_access_iterator_tag> operator+(
1584 typename Iterator<T, N, M, V, Size, std::random_access_iterator_tag>::difference_type
1586 const Iterator<T, N, M, V, Size, std::random_access_iterator_tag> &i)
1601 template <
typename T,
size_t N,
typename MT>
1602 struct ReplaceTypes<T, N, MT, Category::ForwardIterator>
1604 using type = IteratorDetails::Iterator<T, N>;
1606 template <
typename T,
size_t N,
typename MT>
1607 struct ReplaceTypes<T, N, MT, Category::BidirectionalIterator>
1609 using type = IteratorDetails::Iterator<T, N>;
1611 template <
typename T,
size_t N,
typename MT>
1612 struct ReplaceTypes<T, N, MT, Category::RandomAccessIterator>
1614 using type = IteratorDetails::Iterator<T, N>;
1620 template <Vc::Operator Op,
typename S,
typename T, std::size_t N,
typename M,
typename U,
1622 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size<S>() && M::size() == N),
void>
1623 conditional_assign(Adapter<S, T, N> &,
const M &,
const U &)
1626 template <Vc::Operator Op,
typename S,
typename T, std::size_t N,
typename M,
typename U,
1627 std::size_t Offset = 0>
1628 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size<S>() && M::size() == N),
void>
1629 conditional_assign(Adapter<S, T, N> &lhs,
const M &mask,
const U &rhs)
1631 using V =
typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1632 using M2 =
typename V::mask_type;
1633 conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask), get_dispatcher<Offset>(rhs));
1634 conditional_assign<Op, S, T, N, M, U, Offset + 1>(lhs, mask, rhs);
1636 template <Vc::Operator Op,
typename S,
typename T, std::size_t N,
typename M,
1638 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size<S>() && M::size() == N),
void>
1639 conditional_assign(Adapter<S, T, N> &,
const M &)
1642 template <Vc::Operator Op,
typename S,
typename T, std::size_t N,
typename M,
1643 std::size_t Offset = 0>
1644 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size<S>() && M::size() == N),
void>
1645 conditional_assign(Adapter<S, T, N> &lhs,
const M &mask)
1647 using V =
typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1648 using M2 =
typename V::mask_type;
1649 conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask));
1650 conditional_assign<Op, S, T, N, M, Offset + 1>(lhs, mask);
1674 template <
typename T,
size_t N = 0,
typename MT =
void>
1675 using simdize = SimdizeDetail::simdize<T, N, MT>;
1696 #define Vc_SIMDIZE_INTERFACE(MEMBERS__) \
1697 template <std::size_t N__> \
1698 inline auto vc_get__()->decltype(std::get<N__>(std::tie MEMBERS__)) \
1700 return std::get<N__>(std::tie MEMBERS__); \
1702 template <std::size_t N__> \
1703 inline auto vc_get__() const->decltype(std::get<N__>(std::tie MEMBERS__)) \
1705 return std::get<N__>(std::tie MEMBERS__); \
1707 enum : std::size_t { \
1708 tuple_size = std::tuple_size<decltype(std::tie MEMBERS__)>::value \
1715 using Vc::SimdizeDetail::swap;
1718 #endif // VC_COMMON_SIMDIZE_H_
void free(T *p)
Frees memory that was allocated with Vc::malloc.
bool operator<(const Iterator &rhs) const
Returns whether all entries accessed via iterator dereferencing come before the iterator rhs...
SimdizeDetail::simdize< T, N, MT > simdize
Iterator operator--(int)
Postfix overload of the above.
S extract(const Adapter< S, T, N > &a, size_t i)
Extracts and returns one scalar object from a SIMD slot at offset i in the simdized object a...
An allocator that uses global new and supports over-aligned types, as per [C++11 20.6.9].
void assign(Adapter< S, T, N > &a, size_t i, const S &x)
Assigns one scalar object x to a SIMD slot at offset i in the simdized object a.
Iterator & operator--()
Advances the iterator by one vector width, or respectively N scalar steps.
Adapter< S, T, N > shifted(const Adapter< S, T, N > &a, int shift)
Returns a new vectorized object where each entry is shifted by shift.
Vector Classes Namespace.
This is the iterator type created when applying simdize to a bidirectional iterator type...