29 #ifndef VC_COMMON_SIMDIZE_H_
30 #define VC_COMMON_SIMDIZE_H_
90 namespace Vc_VERSIONED_NAMESPACE
98 namespace SimdizeDetail
105 using std::is_base_of;
106 using std::false_type;
107 using std::true_type;
108 using std::iterator_traits;
109 using std::conditional;
111 template <
bool B,
typename T,
typename F>
112 using conditional_t =
typename conditional<B, T, F>::type;
118 template <
typename... Ts>
struct Typelist;
123 enum class Category {
127 ArithmeticVectorizable,
135 BidirectionalIterator,
137 RandomAccessIterator,
146 template <
typename T,
147 typename ItCat =
typename iterator_traits<T>::iterator_category>
148 constexpr Category iteratorCategories(
int)
150 return is_base_of<std::random_access_iterator_tag, ItCat>::value
151 ? Category::RandomAccessIterator
152 : is_base_of<std::bidirectional_iterator_tag, ItCat>::value
153 ? Category::BidirectionalIterator
154 : is_base_of<std::forward_iterator_tag, ItCat>::value
155 ? Category::ForwardIterator
156 : is_base_of<std::output_iterator_tag, ItCat>::value
157 ? Category::OutputIterator
158 : is_base_of<std::input_iterator_tag, ItCat>::value
159 ? Category::InputIterator
165 template <
typename T> constexpr Category iteratorCategories(...)
167 return Category::None;
173 template <
typename T>
struct is_class_template :
public false_type
176 template <
template <
typename...>
class C,
typename... Ts>
177 struct is_class_template<C<Ts...>> :
public true_type
184 template <
typename T> constexpr Category typeCategory()
186 return (is_same<T, bool>::value || is_same<T, short>::value ||
187 is_same<T, unsigned short>::value || is_same<T, int>::value ||
188 is_same<T, unsigned int>::value || is_same<T, float>::value ||
189 is_same<T, double>::value)
190 ? Category::ArithmeticVectorizable
191 : iteratorCategories<T>(int()) != Category::None
192 ? iteratorCategories<T>(
int())
193 : is_class_template<T>::value ? Category::ClassTemplate
202 template <typename T, size_t TupleSize = std::tuple_size<T>::value>
203 constexpr
size_t determine_tuple_size()
207 template <
typename T,
size_t TupleSize = T::tuple_size>
208 constexpr
size_t determine_tuple_size(
size_t = T::tuple_size)
215 template <
typename T>
struct The_simdization_for_the_requested_type_is_not_implemented;
230 template <
typename T,
size_t N,
typename MT, Category = typeCategory<T>()>
231 struct ReplaceTypes :
public The_simdization_for_the_requested_type_is_not_implemented<T>
239 template <
typename T,
size_t N,
typename MT>
struct ReplaceTypes<T, N, MT, Category::None>
248 template <
typename T,
size_t N = 0,
typename MT =
void>
249 using simdize =
typename SimdizeDetail::ReplaceTypes<T, N, MT>::type;
255 template <
typename T,
size_t N,
typename MT>
256 struct ReplaceTypes<T, N, MT, Category::ArithmeticVectorizable>
257 :
public conditional<(N == 0 || Vector<T>::size() == N), Vector<T>, SimdArray<T, N>>
265 template <
size_t N,
typename MT>
266 struct ReplaceTypes<bool, N, MT, Category::ArithmeticVectorizable>
267 :
public conditional<(N == 0 || Mask<MT>::size() == N), Mask<MT>,
268 SimdMaskArray<MT, N>>
275 struct ReplaceTypes<bool, N, void, Category::ArithmeticVectorizable>
276 :
public ReplaceTypes<bool, N, float, Category::ArithmeticVectorizable>
286 template <
size_t N,
typename MT,
typename Replaced,
typename... Remaining>
287 struct SubstituteOneByOne;
293 template <
size_t N,
typename MT,
typename... Replaced,
typename T,
294 typename... Remaining>
295 struct SubstituteOneByOne<N, MT, Typelist<Replaced...>, T, Remaining...>
302 template <
typename U,
size_t M = U::size()>
303 static std::integral_constant<size_t, M> size_or_0(
int);
304 template <
typename U>
static std::integral_constant<size_t, 0> size_or_0(...);
307 using V = simdize<T, N, MT>;
313 static constexpr
auto NewN = N != 0 ? N : decltype(size_or_0<V>(
int()))::value;
320 typedef conditional_t<(N != NewN && is_same<MT, void>::value),
321 conditional_t<is_same<T, bool>::value,
float, T>, MT> NewMT;
327 using type =
typename SubstituteOneByOne<NewN, NewMT, Typelist<Replaced..., V>,
333 template <
size_t Size,
typename... Replaced>
struct SubstitutedBase;
335 template <
typename Replaced>
struct SubstitutedBase<1, Replaced> {
336 template <
typename ValueT,
template <
typename, ValueT...>
class C, ValueT... Values>
337 using SubstitutedWithValues = C<Replaced, Values...>;
340 template <
typename R0,
typename R1>
struct SubstitutedBase<2, R0, R1>
342 template <
typename ValueT,
template <
typename,
typename, ValueT...>
class C,
344 using SubstitutedWithValues = C<R0, R1, Values...>;
347 template <
typename R0,
typename R1,
typename R2>
struct SubstitutedBase<3, R0, R1, R2>
349 template <
typename ValueT,
template <
typename,
typename,
typename, ValueT...>
class C,
351 using SubstitutedWithValues = C<R0, R1, R2, Values...>;
354 template <
typename... Replaced>
struct SubstitutedBase<4, Replaced...> {
356 template <
typename ValueT,
357 template <
typename,
typename,
typename,
typename, ValueT...>
class C,
359 using SubstitutedWithValues = C<Replaced..., Values...>;
363 template <
typename... Replaced>
struct SubstitutedBase<5, Replaced...> {
365 template <
typename ValueT,
template <
typename,
typename,
typename,
typename,
typename,
368 using SubstitutedWithValues = C<Replaced..., Values...>;
372 template <
typename... Replaced>
struct SubstitutedBase<6, Replaced...> {
374 template <
typename ValueT,
template <
typename,
typename,
typename,
typename,
typename,
375 typename, ValueT...>
class C,
377 using SubstitutedWithValues = C<Replaced..., Values...>;
381 template <
typename... Replaced>
struct SubstitutedBase<7, Replaced...> {
383 template <
typename ValueT,
template <
typename,
typename,
typename,
typename,
typename,
384 typename,
typename, ValueT...>
class C,
386 using SubstitutedWithValues = C<Replaced..., Values...>;
390 template <
typename... Replaced>
struct SubstitutedBase<8, Replaced...> {
392 template <
typename ValueT,
template <
typename,
typename,
typename,
typename,
typename,
393 typename,
typename,
typename, ValueT...>
class C,
395 using SubstitutedWithValues = C<Replaced..., Values...>;
404 template <
size_t N_,
typename MT,
typename Replaced0,
typename... Replaced>
405 struct SubstituteOneByOne<N_, MT, Typelist<Replaced0, Replaced...>>
411 :
public SubstitutedBase<sizeof...(Replaced) + 1, Replaced0, Replaced...> {
412 static constexpr
auto N = N_;
417 template <
template <
typename...>
class C>
418 using Substituted = C<Replaced0, Replaced...>;
438 template <
typename Scalar,
typename Base,
size_t N>
class Adapter;
444 template <
template <
typename...>
class C,
typename... Ts,
size_t N,
typename MT>
445 struct ReplaceTypes<C<Ts...>, N, MT, Category::ClassTemplate>
448 using SubstitutionResult =
449 typename SubstituteOneByOne<N, MT, Typelist<>, Ts...>::type;
455 using Vectorized =
typename SubstitutionResult::template Substituted<C>;
461 using type = conditional_t<is_same<C<Ts...>, Vectorized>::value, C<Ts...>,
462 Adapter<C<Ts...>, Vectorized, SubstitutionResult::N>>;
472 #define Vc_DEFINE_NONTYPE_REPLACETYPES_(ValueType_) \
473 template <template <typename, ValueType_...> class C, typename T, ValueType_ Value0, \
474 ValueType_... Values> \
475 struct is_class_template<C<T, Value0, Values...>> : public true_type { \
477 template <template <typename, typename, ValueType_...> class C, typename T0, \
478 typename T1, ValueType_ Value0, ValueType_... Values> \
479 struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type { \
481 template <template <typename, typename, typename, ValueType_...> class C, \
482 typename T0, typename T1, typename T2, ValueType_ Value0, \
483 ValueType_... Values> \
484 struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type { \
486 template <template <typename, typename, typename, typename, ValueType_...> class C, \
487 typename T0, typename T1, typename T2, typename T3, ValueType_ Value0, \
488 ValueType_... Values> \
489 struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type { \
491 template <template <typename, typename, typename, typename, typename, ValueType_...> \
493 typename T0, typename T1, typename T2, typename T3, typename T4, \
494 ValueType_ Value0, ValueType_... Values> \
495 struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
496 : public true_type { \
498 template <template <typename, typename, typename, typename, typename, typename, \
499 ValueType_...> class C, \
500 typename T0, typename T1, typename T2, typename T3, typename T4, \
501 typename T5, ValueType_ Value0, ValueType_... Values> \
502 struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
503 : public true_type { \
505 template <template <typename, typename, typename, typename, typename, typename, \
506 typename, ValueType_...> class C, \
507 typename T0, typename T1, typename T2, typename T3, typename T4, \
508 typename T5, typename T6, ValueType_ Value0, ValueType_... Values> \
509 struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
510 : public true_type { \
512 template <template <typename, ValueType_> class C, typename T0, ValueType_ Value0, \
513 size_t N, typename MT> \
514 struct ReplaceTypes<C<T0, Value0>, N, MT, Category::ClassTemplate> { \
515 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
516 typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
518 static constexpr auto NN = tmp::N; \
519 typedef conditional_t<is_same<C<T0, Value0>, Substituted>::value, C<T0, Value0>, \
520 Adapter<C<T0, Value0>, Substituted, NN>> type; \
522 template <template <typename, typename, ValueType_> class C, typename T0, \
523 typename T1, ValueType_ Value0, size_t N, typename MT> \
524 struct ReplaceTypes<C<T0, T1, Value0>, N, MT, Category::ClassTemplate> { \
525 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
526 typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
528 static constexpr auto NN = tmp::N; \
529 typedef conditional_t<is_same<C<T0, T1, Value0>, Substituted>::value, \
531 Adapter<C<T0, T1, Value0>, Substituted, NN>> type; \
533 template <template <typename, typename, typename, ValueType_> class C, typename T0, \
534 typename T1, typename T2, ValueType_ Value0, size_t N, typename MT> \
535 struct ReplaceTypes<C<T0, T1, T2, Value0>, N, MT, Category::ClassTemplate> { \
536 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
537 typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
539 static constexpr auto NN = tmp::N; \
540 typedef conditional_t<is_same<C<T0, T1, T2, Value0>, Substituted>::value, \
541 C<T0, T1, T2, Value0>, \
542 Adapter<C<T0, T1, T2, Value0>, Substituted, NN>> type; \
545 #define Vc_DEFINE_NONTYPE_REPLACETYPES_(ValueType_) \
546 template <template <typename, ValueType_...> class C, typename T, ValueType_ Value0, \
547 ValueType_... Values> \
548 struct is_class_template<C<T, Value0, Values...>> : public true_type { \
550 template <template <typename, typename, ValueType_...> class C, typename T0, \
551 typename T1, ValueType_ Value0, ValueType_... Values> \
552 struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type { \
554 template <template <typename, typename, typename, ValueType_...> class C, \
555 typename T0, typename T1, typename T2, ValueType_ Value0, \
556 ValueType_... Values> \
557 struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type { \
559 template <template <typename, typename, typename, typename, ValueType_...> class C, \
560 typename T0, typename T1, typename T2, typename T3, ValueType_ Value0, \
561 ValueType_... Values> \
562 struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type { \
564 template <template <typename, typename, typename, typename, typename, ValueType_...> \
566 typename T0, typename T1, typename T2, typename T3, typename T4, \
567 ValueType_ Value0, ValueType_... Values> \
568 struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
569 : public true_type { \
571 template <template <typename, typename, typename, typename, typename, typename, \
572 ValueType_...> class C, \
573 typename T0, typename T1, typename T2, typename T3, typename T4, \
574 typename T5, ValueType_ Value0, ValueType_... Values> \
575 struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
576 : public true_type { \
578 template <template <typename, typename, typename, typename, typename, typename, \
579 typename, ValueType_...> class C, \
580 typename T0, typename T1, typename T2, typename T3, typename T4, \
581 typename T5, typename T6, ValueType_ Value0, ValueType_... Values> \
582 struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
583 : public true_type { \
585 template <template <typename, ValueType_...> class C, typename T0, \
586 ValueType_ Value0, ValueType_... Values, size_t N, typename MT> \
587 struct ReplaceTypes<C<T0, Value0, Values...>, N, MT, Category::ClassTemplate> { \
588 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
589 typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
590 Values...> Substituted; \
591 static constexpr auto NN = tmp::N; \
592 typedef conditional_t<is_same<C<T0, Value0, Values...>, Substituted>::value, \
593 C<T0, Value0, Values...>, \
594 Adapter<C<T0, Value0, Values...>, Substituted, NN>> type; \
596 template <template <typename, typename, ValueType_...> class C, typename T0, \
597 typename T1, ValueType_ Value0, ValueType_... Values, size_t N, \
599 struct ReplaceTypes<C<T0, T1, Value0, Values...>, N, MT, Category::ClassTemplate> { \
600 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
601 typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
602 Values...> Substituted; \
603 static constexpr auto NN = tmp::N; \
604 typedef conditional_t<is_same<C<T0, T1, Value0, Values...>, Substituted>::value, \
605 C<T0, T1, Value0, Values...>, \
606 Adapter<C<T0, T1, Value0, Values...>, Substituted, NN>> \
609 template <template <typename, typename, typename, ValueType_...> class C, \
610 typename T0, typename T1, typename T2, ValueType_ Value0, \
611 ValueType_... Values, size_t N, typename MT> \
612 struct ReplaceTypes<C<T0, T1, T2, Value0, Values...>, N, MT, \
613 Category::ClassTemplate> { \
614 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
615 typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
616 Values...> Substituted; \
617 static constexpr auto NN = tmp::N; \
618 typedef conditional_t< \
619 is_same<C<T0, T1, T2, Value0, Values...>, Substituted>::value, \
620 C<T0, T1, T2, Value0, Values...>, \
621 Adapter<C<T0, T1, T2, Value0, Values...>, Substituted, NN>> type; \
624 Vc_DEFINE_NONTYPE_REPLACETYPES_(
bool);
625 Vc_DEFINE_NONTYPE_REPLACETYPES_(
wchar_t);
626 Vc_DEFINE_NONTYPE_REPLACETYPES_(
char);
627 Vc_DEFINE_NONTYPE_REPLACETYPES_(
signed char);
628 Vc_DEFINE_NONTYPE_REPLACETYPES_(
unsigned char);
629 Vc_DEFINE_NONTYPE_REPLACETYPES_(
signed short);
630 Vc_DEFINE_NONTYPE_REPLACETYPES_(
unsigned short);
631 Vc_DEFINE_NONTYPE_REPLACETYPES_(
signed int);
632 Vc_DEFINE_NONTYPE_REPLACETYPES_(
unsigned int);
633 Vc_DEFINE_NONTYPE_REPLACETYPES_(
signed long);
634 Vc_DEFINE_NONTYPE_REPLACETYPES_(
unsigned long);
635 Vc_DEFINE_NONTYPE_REPLACETYPES_(
signed long long);
636 Vc_DEFINE_NONTYPE_REPLACETYPES_(
unsigned long long);
637 #undef Vc_DEFINE_NONTYPE_REPLACETYPES_
641 template <
typename Class,
typename... Args>
642 constexpr
bool is_constructible_with_single_brace()
646 template <
typename Class,
typename... Args>
647 constexpr
bool is_constructible_with_double_brace()
652 namespace is_constructible_with_single_brace_impl
654 template <
typename T> T create();
655 template <
typename Class,
typename... Args,
656 typename = decltype((Class{create<Args>()...}))>
657 std::true_type test(
int);
658 template <
typename Class,
typename... Args> std::false_type test(...);
661 template <
typename Class,
typename... Args>
662 constexpr
bool is_constructible_with_single_brace()
665 is_constructible_with_single_brace_impl::test<Class, Args...>(1))::value;
668 is_constructible_with_single_brace<std::tuple<int, int, int>,
int,
int,
int>(),
"");
669 static_assert(is_constructible_with_single_brace<std::array<int, 3>,
int,
int,
int>(),
672 namespace is_constructible_with_double_brace_impl
674 template <
typename T> T create();
675 template <
typename Class,
typename... Args,
676 typename = decltype(Class{{create<Args>()...}})>
677 std::true_type test(
int);
678 template <
typename Class,
typename... Args> std::false_type test(...);
681 template <
typename Class,
typename... Args>
682 constexpr
bool is_constructible_with_double_brace()
685 is_constructible_with_double_brace_impl::test<Class, Args...>(1))::value;
688 !is_constructible_with_double_brace<std::tuple<int, int, int>,
int,
int,
int>(),
"");
689 static_assert(is_constructible_with_double_brace<std::array<int, 3>,
int,
int,
int>(),
693 template <
size_t I,
typename T,
694 typename R = decltype(std::declval<T &>().
template vc_get_<I>())>
695 R get_dispatcher(T &x,
void * =
nullptr)
697 return x.template vc_get_<I>();
699 template <
size_t I,
typename T,
700 typename R = decltype(std::declval<const T &>().
template vc_get_<I>())>
701 R get_dispatcher(
const T &x,
void * =
nullptr)
703 return x.template vc_get_<I>();
705 template <
size_t I,
typename T,
typename R = decltype(std::get<I>(std::declval<T &>()))>
706 R get_dispatcher(T &x,
int = 0)
708 return std::get<I>(x);
710 template <
size_t I,
typename T,
711 typename R = decltype(std::get<I>(std::declval<const T &>()))>
712 R get_dispatcher(
const T &x,
int = 0)
714 return std::get<I>(x);
719 template <
typename Scalar,
typename Base,
size_t N>
class Adapter :
public Base
723 template <std::size_t... Indexes,
typename T>
724 Adapter(Vc::index_sequence<Indexes...>,
const Scalar &x_, T, std::true_type)
725 : Base{{get_dispatcher<Indexes>(x_)...}}
730 template <std::size_t... Indexes>
731 Adapter(Vc::index_sequence<Indexes...>,
const Scalar &x_, std::true_type,
733 : Base{get_dispatcher<Indexes>(x_)...}
738 template <std::size_t... Indexes>
739 Adapter(Vc::index_sequence<Indexes...>,
const Scalar &x_, std::false_type,
741 : Base(get_dispatcher<Indexes>(x_)...)
745 template <std::size_t... Indexes>
746 Adapter(Vc::index_sequence<Indexes...> seq_,
const Scalar &x_)
748 std::integral_constant<
749 bool, is_constructible_with_single_brace<
750 Base, decltype(get_dispatcher<Indexes>(
751 std::declval<const Scalar &>()))...>()>(),
752 std::integral_constant<
753 bool, is_constructible_with_double_brace<
754 Base, decltype(get_dispatcher<Indexes>(
755 std::declval<const Scalar &>()))...>()>())
761 static constexpr
size_t size() {
return N; }
764 using base_type = Base;
767 using scalar_type = Scalar;
774 #if defined Vc_CLANG && Vc_CLANG < 0x30700
775 Vc_INTRINSIC Adapter(
const Adapter &x) : Base(x) {}
777 Adapter(
const Adapter &) =
default;
779 Adapter(Adapter &&) =
default;
782 Adapter &operator=(
const Adapter &) =
default;
784 Adapter &operator=(Adapter &&) =
default;
787 template <
typename U,
size_t TupleSize = determine_tuple_size<Scalar>(),
788 typename Seq = Vc::make_index_sequence<TupleSize>,
789 typename = enable_if<std::is_convertible<U, Scalar>::value>>
791 : Adapter(Seq(), static_cast<const Scalar &>(x_))
796 template <
typename A0,
typename... Args,
797 typename =
typename std::enable_if<
798 !Traits::is_index_sequence<A0>::value &&
799 (
sizeof...(Args) > 0 || !std::is_convertible<A0, Scalar>::value)>::type>
800 Adapter(A0 &&arg0_, Args &&... arguments_)
801 : Base(
std::forward<A0>(arg0_),
std::forward<Args>(arguments_)...)
806 template <
typename T,
807 typename = decltype(Base(std::declval<
const std::initializer_list<T> &>()))>
808 Adapter(
const std::initializer_list<T> &l_)
815 void *
operator new(
size_t size)
817 return Vc::Common::aligned_malloc<alignof(Adapter)>(size);
819 void *
operator new(size_t,
void *p_) {
return p_; }
820 void *
operator new[](
size_t size)
822 return Vc::Common::aligned_malloc<alignof(Adapter)>(size);
824 void *
operator new[](size_t ,
void *p_) {
return p_; }
826 void operator delete(
void *,
void *) {}
828 void operator delete[](
void *,
void *) {}
835 template <
class... TTypes,
class... TTypesV,
class... UTypes,
class... UTypesV,
size_t N>
836 inline bool operator==(
837 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
838 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) =
delete;
839 template <
class... TTypes,
class... TTypesV,
class... UTypes,
class... UTypesV,
size_t N>
840 inline bool operator!=(
841 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
842 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) =
delete;
843 template <
class... TTypes,
class... TTypesV,
class... UTypes,
class... UTypesV,
size_t N>
844 inline bool operator<=(
845 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
846 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) =
delete;
847 template <
class... TTypes,
class... TTypesV,
class... UTypes,
class... UTypesV,
size_t N>
848 inline bool operator>=(
849 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
850 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) =
delete;
851 template <
class... TTypes,
class... TTypesV,
class... UTypes,
class... UTypesV,
size_t N>
852 inline bool operator<(
853 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
854 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) =
delete;
855 template <
class... TTypes,
class... TTypesV,
class... UTypes,
class... UTypesV,
size_t N>
856 inline bool operator>(
857 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
858 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) =
delete;
869 template <
typename Scalar,
typename Base,
size_t N>
870 class tuple_size<
Vc::SimdizeDetail::Adapter<Scalar, Base, N>> :
public tuple_size<Base>
876 template <
size_t I,
typename Scalar,
typename Base,
size_t N>
877 class tuple_element<I,
Vc::SimdizeDetail::Adapter<Scalar, Base, N>>
878 :
public tuple_element<I, Base>
888 template <
typename S,
typename T,
size_t N>
889 class allocator<
Vc::SimdizeDetail::Adapter<S, T, N>>
893 template <
typename U>
struct rebind
895 typedef std::allocator<U> other;
900 namespace Vc_VERSIONED_NAMESPACE
902 namespace SimdizeDetail
912 template <
typename T>
static inline T decay_workaround(
const T &x) {
return x; }
917 template <
typename S,
typename T,
size_t N,
size_t... Indexes>
918 inline void assign_impl(Adapter<S, T, N> &a,
size_t i,
const S &x,
919 Vc::index_sequence<Indexes...>)
921 const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(x)))...> tmp(
922 decay_workaround(get_dispatcher<Indexes>(x))...);
923 auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(tmp), 0)...};
924 if (&unused == &unused) {}
931 template <
typename S,
typename T,
size_t N>
932 inline void assign(Adapter<S, T, N> &a,
size_t i,
const S &x)
934 assign_impl(a, i, x, Vc::make_index_sequence<determine_tuple_size<T>()>());
939 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
940 Vc_INTRINSIC
void assign(V &v,
size_t i,
typename V::EntryType x)
948 template <
typename S,
typename T,
size_t N,
size_t... Indexes>
949 inline S extract_impl(
const Adapter<S, T, N> &a,
size_t i, Vc::index_sequence<Indexes...>)
951 const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[i]))...> tmp(
952 decay_workaround(get_dispatcher<Indexes>(a)[i])...);
953 return S(get_dispatcher<Indexes>(tmp)...);
960 template <
typename S,
typename T,
size_t N>
961 inline S
extract(
const Adapter<S, T, N> &a,
size_t i)
963 return extract_impl(a, i, Vc::make_index_sequence<determine_tuple_size<S>()>());
968 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
969 Vc_INTRINSIC
typename V::EntryType extract(
const V &v,
size_t i)
974 template <
typename S,
typename T, std::size_t N, std::size_t... Indexes>
975 inline Adapter<S, T, N> shifted_impl(
const Adapter<S, T, N> &a,
int shift,
976 Vc::index_sequence<Indexes...>)
979 auto &&unused = {(get_dispatcher<Indexes>(r) = get_dispatcher<Indexes>(a).shifted(shift), 0)...};
980 if (&unused == &unused) {}
992 template <
typename S,
typename T,
size_t N>
993 inline Adapter<S, T, N>
shifted(
const Adapter<S, T, N> &a,
int shift)
995 return shifted_impl(a, shift, Vc::make_index_sequence<determine_tuple_size<T>()>());
1001 template <
typename S,
typename T, std::size_t N, std::size_t... Indexes>
1002 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, S &x,
1003 Vc::index_sequence<Indexes...>)
1005 const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[0]))...> tmp{
1006 decay_workaround(get_dispatcher<Indexes>(a)[i])...};
1007 auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(x), 0)...};
1008 auto &&unused2 = {(get_dispatcher<Indexes>(x) = get_dispatcher<Indexes>(tmp), 0)...};
1009 if (&unused == &unused2) {}
1011 template <
typename S,
typename T, std::size_t N, std::size_t... Indexes>
1012 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b,
1013 std::size_t j, Vc::index_sequence<Indexes...>)
1015 const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[0]))...> tmp{
1016 decay_workaround(get_dispatcher<Indexes>(a)[i])...};
1017 auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(b)[j], 0)...};
1018 auto &&unused2 = {(get_dispatcher<Indexes>(b)[j] = get_dispatcher<Indexes>(tmp), 0)...};
1019 if (&unused == &unused2) {}
1026 template <
typename S,
typename T, std::
size_t N>
1027 inline void swap(Adapter<S, T, N> &a, std::size_t i, S &x)
1029 swap_impl(a, i, x, Vc::make_index_sequence<determine_tuple_size<T>()>());
1031 template <
typename S,
typename T, std::
size_t N>
1032 inline void swap(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b, std::size_t j)
1034 swap_impl(a, i, b, j, Vc::make_index_sequence<determine_tuple_size<T>()>());
1037 template <
typename A>
class Scalar
1039 using reference =
typename std::add_lvalue_reference<A>::type;
1040 using S =
typename A::scalar_type;
1041 using IndexSeq = Vc::make_index_sequence<determine_tuple_size<S>()>;
1044 Scalar(reference aa,
size_t ii) : a(aa), i(ii) {}
1047 Scalar(
const Scalar &) =
delete;
1048 Scalar(Scalar &&) =
delete;
1049 Scalar &operator=(
const Scalar &) =
delete;
1050 Scalar &operator=(Scalar &&) =
delete;
1052 void operator=(
const S &x) { assign_impl(a, i, x, IndexSeq()); }
1053 operator S()
const {
return extract_impl(a, i, IndexSeq()); }
1055 template <
typename AA>
1056 friend inline void swap(Scalar<AA> &&a,
typename AA::scalar_type &b);
1057 template <
typename AA>
1058 friend inline void swap(
typename AA::scalar_type &b, Scalar<AA> &&a);
1059 template <
typename AA>
friend inline void swap(Scalar<AA> &&a, Scalar<AA> &&b);
1068 template <
typename A>
inline void swap(Scalar<A> &&a,
typename A::scalar_type &b)
1070 swap_impl(a.a, a.i, b,
typename Scalar<A>::IndexSeq());
1074 template <
typename A>
inline void swap(
typename A::scalar_type &b, Scalar<A> &&a)
1076 swap_impl(a.a, a.i, b,
typename Scalar<A>::IndexSeq());
1079 template <
typename A>
inline void swap(Scalar<A> &&a, Scalar<A> &&b)
1081 swap_impl(a.a, a.i, b.a, b.i,
typename Scalar<A>::IndexSeq());
1084 template <
typename A>
class Interface
1086 using reference =
typename std::add_lvalue_reference<A>::type;
1088 Vc::make_index_sequence<determine_tuple_size<typename A::scalar_type>()>;
1091 Interface(reference aa) : a(aa) {}
1093 Scalar<A> operator[](
size_t i)
1097 typename A::scalar_type operator[](
size_t i)
const
1099 return extract_impl(a, i, IndexSeq());
1104 return shifted_impl(a, amount, IndexSeq());
1111 template <
typename S,
typename T,
size_t N>
1112 Interface<Adapter<S, T, N>> decorate(Adapter<S, T, N> &a)
1116 template <
typename S,
typename T,
size_t N>
1117 const Interface<const Adapter<S, T, N>> decorate(
const Adapter<S, T, N> &a)
1122 namespace IteratorDetails
1124 enum class Mutable { Yes, No };
1126 template <
typename It,
typename V,
size_t I,
size_t End>
1127 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I == End), It>)
1131 template <
typename It,
typename V,
size_t I,
size_t End>
1132 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I < End), It> it)
1134 V r = fromIteratorImpl<It, V, I + 1, End>(it);
1135 Traits::decay<decltype(get_dispatcher<I>(r))> tmp;
1136 for (
size_t j = 0; j < V::size(); ++j, ++it) {
1137 tmp[j] = get_dispatcher<I>(*it);
1139 get_dispatcher<I>(r) = tmp;
1142 template <
typename It,
typename V>
1143 Vc_INTRINSIC V fromIterator(enable_if<!Traits::is_simd_vector<V>::value,
const It &> it)
1145 return fromIteratorImpl<It, V, 0, determine_tuple_size<V>()>(it);
1147 template <
typename It,
typename V>
1148 Vc_INTRINSIC V fromIterator(enable_if<Traits::is_simd_vector<V>::value, It> it)
1151 for (
size_t j = 0; j < V::size(); ++j, ++it) {
1160 template <
typename T,
typename value_vector, Mutable>
class Pointer;
1170 template <
typename T,
typename value_vector>
class Pointer<T, value_vector, Mutable::Yes>
1172 static constexpr
auto Size = value_vector::size();
1176 value_vector *operator->() {
return &data; }
1183 Pointer(
const Pointer &) =
delete;
1184 Pointer &operator=(
const Pointer &) =
delete;
1185 Pointer &operator=(Pointer &&) =
delete;
1188 Pointer(Pointer &&) =
default;
1198 for (
size_t i = 0; i < Size; ++i, ++begin_iterator) {
1199 *begin_iterator =
extract(data, i);
1204 Pointer(
const T &it) : data(fromIterator<T, value_vector>(it)), begin_iterator(it) {}
1217 template <
typename T,
typename value_vector>
class Pointer<T, value_vector, Mutable::No>
1219 static constexpr
auto Size = value_vector::size();
1222 const value_vector *operator->()
const {
return &data; }
1225 Pointer(
const Pointer &) =
delete;
1226 Pointer &operator=(
const Pointer &) =
delete;
1227 Pointer &operator=(Pointer &&) =
delete;
1229 Pointer(Pointer &&) =
default;
1231 Pointer(
const T &it) : data(fromIterator<T, value_vector>(it)) {}
1249 template <
typename T,
typename value_vector, Mutable M>
class Reference;
1252 template <
typename T,
typename value_vector>
1253 class Reference<T, value_vector, Mutable::Yes> :
public value_vector
1255 static constexpr
auto Size = value_vector::size();
1257 using reference =
typename std::add_lvalue_reference<T>::type;
1258 reference scalar_it;
1263 Reference(reference first_it)
1264 : value_vector(fromIterator<T, value_vector>(first_it)), scalar_it(first_it)
1269 Reference(
const Reference &) =
delete;
1270 Reference(Reference &&) =
default;
1271 Reference &operator=(
const Reference &) =
delete;
1272 Reference &operator=(Reference &&) =
delete;
1279 void operator=(
const value_vector &x)
1281 static_cast<value_vector &
>(*this) = x;
1282 auto it = scalar_it;
1283 for (
size_t i = 0; i < Size; ++i, ++it) {
1288 #define Vc_OP(op_) \
1289 template <typename T0, typename V0, typename T1, typename V1> \
1290 decltype(std::declval<const V0 &>() op_ std::declval<const V1 &>()) operator op_( \
1291 const Reference<T0, V0, Mutable::Yes> &x, \
1292 const Reference<T1, V1, Mutable::Yes> &y) \
1294 return static_cast<const V0 &>(x) op_ static_cast<const V1 &>(y); \
1296 Vc_ALL_COMPARES(Vc_OP);
1297 Vc_ALL_ARITHMETICS(Vc_OP);
1298 Vc_ALL_BINARY(Vc_OP);
1299 Vc_ALL_LOGICAL(Vc_OP);
1300 Vc_ALL_SHIFTS(Vc_OP);
1304 template <
typename T,
typename value_vector>
1305 class Reference<T, value_vector, Mutable::No> :
public value_vector
1307 static constexpr
auto Size = value_vector::size();
1310 Reference(
const T &it) : value_vector(fromIterator<T, value_vector>(it)) {}
1312 Reference(
const Reference &) =
delete;
1313 Reference(Reference &&) =
default;
1314 Reference &operator=(
const Reference &) =
delete;
1315 Reference &operator=(Reference &&) =
delete;
1318 void operator=(
const value_vector &x) =
delete;
1321 template <
typename T,
size_t N,
1322 IteratorDetails::Mutable M =
1323 (Traits::is_output_iterator<T>::value ? Mutable::Yes : Mutable::No),
1324 typename V = simdize<
typename std::iterator_traits<T>::value_type, N>,
1325 size_t Size = V::size(),
1326 typename =
typename std::iterator_traits<T>::iterator_category>
1329 template <
typename T,
size_t N, IteratorDetails::Mutable M,
typename V,
size_t Size>
1330 class Iterator<T, N, M, V, Size,
std::forward_iterator_tag>
1331 :
public std::iterator<typename std::iterator_traits<T>::iterator_category, V,
1332 typename std::iterator_traits<T>::difference_type,
1333 IteratorDetails::Pointer<T, V, M>,
1334 IteratorDetails::Reference<T, V, M>>
1337 using pointer = IteratorDetails::Pointer<T, V, M>;
1338 using reference = IteratorDetails::Reference<T, V, M>;
1339 using const_pointer = IteratorDetails::Pointer<T, V, IteratorDetails::Mutable::No>;
1340 using const_reference =
1341 IteratorDetails::Reference<T, V, IteratorDetails::Mutable::No>;
1344 static constexpr std::size_t size() {
return Size; }
1346 Iterator() =
default;
1354 Iterator(
const T &x) : scalar_it(x) {}
1358 Iterator(T &&x) : scalar_it(
std::move(x)) {}
1362 Iterator &operator=(
const T &x)
1370 Iterator &operator=(T &&x)
1372 scalar_it = std::move(x);
1377 Iterator(
const Iterator &) =
default;
1379 Iterator(Iterator &&) =
default;
1381 Iterator &operator=(
const Iterator &) =
default;
1383 Iterator &operator=(Iterator &&) =
default;
1386 Iterator &operator++()
1388 std::advance(scalar_it, Size);
1392 Iterator operator++(
int)
1394 Iterator copy(*
this);
1407 bool operator==(
const Iterator &rhs)
const
1410 for (
size_t i = 1; i < Size; ++i) {
1411 Vc_ASSERT((++it != rhs.scalar_it));
1413 return scalar_it == rhs.scalar_it;
1423 bool operator!=(
const Iterator &rhs)
const
1426 for (
size_t i = 1; i < Size; ++i) {
1427 Vc_ASSERT((++it != rhs.scalar_it));
1429 return scalar_it != rhs.scalar_it;
1432 pointer operator->() {
return scalar_it; }
1440 reference
operator*() {
return scalar_it; }
1442 const_pointer operator->()
const {
return scalar_it; }
1451 const_reference
operator*()
const {
return scalar_it; }
1466 operator const T &()
const {
return scalar_it; }
1476 template <
typename T,
size_t N, IteratorDetails::Mutable M,
typename V,
size_t Size>
1477 class Iterator<T, N, M, V, Size,
std::bidirectional_iterator_tag>
1478 :
public Iterator<T, N, M, V, Size, std::forward_iterator_tag>
1480 using Base = Iterator<T, N, M, V, Size, std::forward_iterator_tag>;
1483 using Base::scalar_it;
1486 using pointer =
typename Base::pointer;
1487 using reference =
typename Base::reference;
1488 using const_pointer =
typename Base::const_pointer;
1489 using const_reference =
typename Base::const_reference;
1491 using Iterator<T, N, M, V, Size,
1492 std::forward_iterator_tag>::Iterator;
1498 std::advance(scalar_it, -Size);
1504 Iterator copy(*
this);
1514 template <
typename T,
size_t N, IteratorDetails::Mutable M,
typename V,
size_t Size>
1515 class Iterator<T, N, M, V, Size,
std::random_access_iterator_tag>
1516 :
public Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1521 using Base::scalar_it;
1524 using pointer =
typename Base::pointer;
1525 using reference =
typename Base::reference;
1526 using const_pointer =
typename Base::const_pointer;
1527 using const_reference =
typename Base::const_reference;
1528 using difference_type =
typename std::iterator_traits<T>::difference_type;
1533 Iterator &operator+=(difference_type n)
1535 scalar_it += n * Size;
1538 Iterator
operator+(difference_type n)
const {
return Iterator(*
this) += n; }
1540 Iterator &operator-=(difference_type n)
1542 scalar_it -= n * Size;
1545 Iterator
operator-(difference_type n)
const {
return Iterator(*
this) -= n; }
1547 difference_type
operator-(
const Iterator &rhs)
const
1549 constexpr difference_type n = Size;
1550 Vc_ASSERT((scalar_it - rhs.scalar_it) % n ==
1556 return (scalar_it - rhs.scalar_it) / n;
1565 return scalar_it + Size <= rhs.scalar_it;
1568 bool operator>(
const Iterator &rhs)
const
1570 return scalar_it >= rhs.scalar_it + Size;
1573 bool operator<=(
const Iterator &rhs)
const
1575 return scalar_it + (Size - 1) <= rhs.scalar_it;
1578 bool operator>=(
const Iterator &rhs)
const
1580 return scalar_it >= rhs.scalar_it + (Size - 1);
1583 reference operator[](difference_type i) {
return *(*
this + i); }
1584 const_reference operator[](difference_type i)
const {
return *(*
this + i); }
1587 template <
typename T,
size_t N, IteratorDetails::Mutable M,
typename V,
size_t Size>
1588 Iterator<T, N, M, V, Size, std::random_access_iterator_tag>
operator+(
1589 typename Iterator<T, N, M, V, Size, std::random_access_iterator_tag>::difference_type
1591 const Iterator<T, N, M, V, Size, std::random_access_iterator_tag> &i)
1606 template <
typename T,
size_t N,
typename MT>
1607 struct ReplaceTypes<T, N, MT, Category::ForwardIterator>
1609 using type = IteratorDetails::Iterator<T, N>;
1611 template <
typename T,
size_t N,
typename MT>
1612 struct ReplaceTypes<T, N, MT, Category::BidirectionalIterator>
1614 using type = IteratorDetails::Iterator<T, N>;
1616 template <
typename T,
size_t N,
typename MT>
1617 struct ReplaceTypes<T, N, MT, Category::RandomAccessIterator>
1619 using type = IteratorDetails::Iterator<T, N>;
1625 template <Vc::Operator Op,
typename S,
typename T, std::size_t N,
typename M,
typename U,
1627 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size<S>() && M::size() == N),
void>
1628 conditional_assign(Adapter<S, T, N> &,
const M &,
const U &)
1631 template <Vc::Operator Op,
typename S,
typename T, std::size_t N,
typename M,
typename U,
1632 std::size_t Offset = 0>
1633 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size<S>() && M::size() == N),
void>
1634 conditional_assign(Adapter<S, T, N> &lhs,
const M &mask,
const U &rhs)
1636 using V =
typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1637 using M2 =
typename V::mask_type;
1638 conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask), get_dispatcher<Offset>(rhs));
1639 conditional_assign<Op, S, T, N, M, U, Offset + 1>(lhs, mask, rhs);
1641 template <Vc::Operator Op,
typename S,
typename T, std::size_t N,
typename M,
1643 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size<S>() && M::size() == N),
void>
1644 conditional_assign(Adapter<S, T, N> &,
const M &)
1647 template <Vc::Operator Op,
typename S,
typename T, std::size_t N,
typename M,
1648 std::size_t Offset = 0>
1649 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size<S>() && M::size() == N),
void>
1650 conditional_assign(Adapter<S, T, N> &lhs,
const M &mask)
1652 using V =
typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1653 using M2 =
typename V::mask_type;
1654 conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask));
1655 conditional_assign<Op, S, T, N, M, Offset + 1>(lhs, mask);
1679 template <
typename T,
size_t N = 0,
typename MT =
void>
1680 using simdize = SimdizeDetail::simdize<T, N, MT>;
1701 #define Vc_SIMDIZE_INTERFACE(MEMBERS_) \
1702 template <std::size_t N_> \
1703 inline auto vc_get_()->decltype(std::get<N_>(std::tie MEMBERS_)) \
1705 return std::get<N_>(std::tie MEMBERS_); \
1707 template <std::size_t N_> \
1708 inline auto vc_get_() const->decltype(std::get<N_>(std::tie MEMBERS_)) \
1710 return std::get<N_>(std::tie MEMBERS_); \
1712 enum : std::size_t { \
1713 tuple_size = std::tuple_size<decltype(std::tie MEMBERS_)>::value \
1720 using Vc::SimdizeDetail::swap;
1723 #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...
result_vector_type< L, R > operator-(L &&lhs, R &&rhs)
Applies - component-wise and concurrently.
result_vector_type< L, R > operator*(L &&lhs, R &&rhs)
Applies * component-wise and concurrently.
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].
result_vector_type< L, R > operator+(L &&lhs, R &&rhs)
Applies + component-wise and concurrently.
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...