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, ValueType_ Value0, \
480 ValueType_... Values> \
481 struct is_class_template<C<T, Value0, Values...>> : public true_type { \
483 template <template <typename, typename, ValueType_...> class C, typename T0, \
484 typename T1, ValueType_ Value0, ValueType_... Values> \
485 struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type { \
487 template <template <typename, typename, typename, ValueType_...> class C, \
488 typename T0, typename T1, typename T2, ValueType_ Value0, \
489 ValueType_... Values> \
490 struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type { \
492 template <template <typename, typename, typename, typename, ValueType_...> class C, \
493 typename T0, typename T1, typename T2, typename T3, ValueType_ Value0, \
494 ValueType_... Values> \
495 struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type { \
497 template <template <typename, typename, typename, typename, typename, ValueType_...> \
499 typename T0, typename T1, typename T2, typename T3, typename T4, \
500 ValueType_ Value0, ValueType_... Values> \
501 struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
502 : public true_type { \
504 template <template <typename, typename, typename, typename, typename, typename, \
505 ValueType_...> class C, \
506 typename T0, typename T1, typename T2, typename T3, typename T4, \
507 typename T5, ValueType_ Value0, ValueType_... Values> \
508 struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
509 : public true_type { \
511 template <template <typename, typename, typename, typename, typename, typename, \
512 typename, ValueType_...> class C, \
513 typename T0, typename T1, typename T2, typename T3, typename T4, \
514 typename T5, typename T6, ValueType_ Value0, ValueType_... Values> \
515 struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
516 : public true_type { \
518 template <template <typename, ValueType_> class C, typename T0, ValueType_ Value0, \
519 size_t N, typename MT> \
520 struct ReplaceTypes<C<T0, Value0>, N, MT, Category::ClassTemplate> { \
521 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
522 typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
524 static constexpr auto NN = tmp::N; \
525 typedef conditional_t<is_same<C<T0, Value0>, Substituted>::value, C<T0, Value0>, \
526 Adapter<C<T0, Value0>, Substituted, NN>> type; \
528 template <template <typename, typename, ValueType_> class C, typename T0, \
529 typename T1, ValueType_ Value0, size_t N, typename MT> \
530 struct ReplaceTypes<C<T0, T1, Value0>, N, MT, Category::ClassTemplate> { \
531 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
532 typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
534 static constexpr auto NN = tmp::N; \
535 typedef conditional_t<is_same<C<T0, T1, Value0>, Substituted>::value, \
537 Adapter<C<T0, T1, Value0>, Substituted, NN>> type; \
539 template <template <typename, typename, typename, ValueType_> class C, typename T0, \
540 typename T1, typename T2, ValueType_ Value0, size_t N, typename MT> \
541 struct ReplaceTypes<C<T0, T1, T2, Value0>, N, MT, Category::ClassTemplate> { \
542 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
543 typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
545 static constexpr auto NN = tmp::N; \
546 typedef conditional_t<is_same<C<T0, T1, T2, Value0>, Substituted>::value, \
547 C<T0, T1, T2, Value0>, \
548 Adapter<C<T0, T1, T2, Value0>, Substituted, NN>> type; \
551 #define Vc_DEFINE_NONTYPE_REPLACETYPES_(ValueType_) \
552 template <template <typename, ValueType_...> class C, typename T, ValueType_ Value0, \
553 ValueType_... Values> \
554 struct is_class_template<C<T, Value0, Values...>> : public true_type { \
556 template <template <typename, typename, ValueType_...> class C, typename T0, \
557 typename T1, ValueType_ Value0, ValueType_... Values> \
558 struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type { \
560 template <template <typename, typename, typename, ValueType_...> class C, \
561 typename T0, typename T1, typename T2, ValueType_ Value0, \
562 ValueType_... Values> \
563 struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type { \
565 template <template <typename, typename, typename, typename, ValueType_...> class C, \
566 typename T0, typename T1, typename T2, typename T3, ValueType_ Value0, \
567 ValueType_... Values> \
568 struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type { \
570 template <template <typename, typename, typename, typename, typename, ValueType_...> \
572 typename T0, typename T1, typename T2, typename T3, typename T4, \
573 ValueType_ Value0, ValueType_... Values> \
574 struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
575 : public true_type { \
577 template <template <typename, typename, typename, typename, typename, typename, \
578 ValueType_...> class C, \
579 typename T0, typename T1, typename T2, typename T3, typename T4, \
580 typename T5, ValueType_ Value0, ValueType_... Values> \
581 struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
582 : public true_type { \
584 template <template <typename, typename, typename, typename, typename, typename, \
585 typename, ValueType_...> class C, \
586 typename T0, typename T1, typename T2, typename T3, typename T4, \
587 typename T5, typename T6, ValueType_ Value0, ValueType_... Values> \
588 struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
589 : public true_type { \
591 template <template <typename, ValueType_...> class C, typename T0, \
592 ValueType_ Value0, ValueType_... Values, size_t N, typename MT> \
593 struct ReplaceTypes<C<T0, Value0, Values...>, N, MT, Category::ClassTemplate> { \
594 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
595 typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
596 Values...> Substituted; \
597 static constexpr auto NN = tmp::N; \
598 typedef conditional_t<is_same<C<T0, Value0, Values...>, Substituted>::value, \
599 C<T0, Value0, Values...>, \
600 Adapter<C<T0, Value0, Values...>, Substituted, NN>> type; \
602 template <template <typename, typename, ValueType_...> class C, typename T0, \
603 typename T1, ValueType_ Value0, ValueType_... Values, size_t N, \
605 struct ReplaceTypes<C<T0, T1, Value0, Values...>, N, MT, Category::ClassTemplate> { \
606 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
607 typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
608 Values...> Substituted; \
609 static constexpr auto NN = tmp::N; \
610 typedef conditional_t<is_same<C<T0, T1, Value0, Values...>, Substituted>::value, \
611 C<T0, T1, Value0, Values...>, \
612 Adapter<C<T0, T1, Value0, Values...>, Substituted, NN>> \
615 template <template <typename, typename, typename, ValueType_...> class C, \
616 typename T0, typename T1, typename T2, ValueType_ Value0, \
617 ValueType_... Values, size_t N, typename MT> \
618 struct ReplaceTypes<C<T0, T1, T2, Value0, Values...>, N, MT, \
619 Category::ClassTemplate> { \
620 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
621 typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
622 Values...> Substituted; \
623 static constexpr auto NN = tmp::N; \
624 typedef conditional_t< \
625 is_same<C<T0, T1, T2, Value0, Values...>, Substituted>::value, \
626 C<T0, T1, T2, Value0, Values...>, \
627 Adapter<C<T0, T1, T2, Value0, Values...>, Substituted, NN>> type; \
630 Vc_DEFINE_NONTYPE_REPLACETYPES_(
bool);
631 Vc_DEFINE_NONTYPE_REPLACETYPES_(
wchar_t);
632 Vc_DEFINE_NONTYPE_REPLACETYPES_(
char);
633 Vc_DEFINE_NONTYPE_REPLACETYPES_(
signed char);
634 Vc_DEFINE_NONTYPE_REPLACETYPES_(
unsigned char);
635 Vc_DEFINE_NONTYPE_REPLACETYPES_(
signed short);
636 Vc_DEFINE_NONTYPE_REPLACETYPES_(
unsigned short);
637 Vc_DEFINE_NONTYPE_REPLACETYPES_(
signed int);
638 Vc_DEFINE_NONTYPE_REPLACETYPES_(
unsigned int);
639 Vc_DEFINE_NONTYPE_REPLACETYPES_(
signed long);
640 Vc_DEFINE_NONTYPE_REPLACETYPES_(
unsigned long);
641 Vc_DEFINE_NONTYPE_REPLACETYPES_(
signed long long);
642 Vc_DEFINE_NONTYPE_REPLACETYPES_(
unsigned long long);
643 #undef Vc_DEFINE_NONTYPE_REPLACETYPES_
647 template <
typename Class,
typename... Args>
648 constexpr
bool is_constructible_with_single_brace()
652 template <
typename Class,
typename... Args>
653 constexpr
bool is_constructible_with_double_brace()
658 namespace is_constructible_with_single_brace_impl
660 template <
typename T> T create();
661 template <
typename Class,
typename... Args,
662 typename = decltype((Class{create<Args>()...}))>
663 std::true_type test(
int);
664 template <
typename Class,
typename... Args> std::false_type test(...);
667 template <
typename Class,
typename... Args>
668 constexpr
bool is_constructible_with_single_brace()
671 is_constructible_with_single_brace_impl::test<Class, Args...>(1))::value;
674 is_constructible_with_single_brace<std::tuple<int, int, int>,
int,
int,
int>(),
"");
675 static_assert(is_constructible_with_single_brace<std::array<int, 3>,
int,
int,
int>(),
678 namespace is_constructible_with_double_brace_impl
680 template <
typename T> T create();
681 template <
typename Class,
typename... Args,
682 typename = decltype(Class{{create<Args>()...}})>
683 std::true_type test(
int);
684 template <
typename Class,
typename... Args> std::false_type test(...);
687 template <
typename Class,
typename... Args>
688 constexpr
bool is_constructible_with_double_brace()
691 is_constructible_with_double_brace_impl::test<Class, Args...>(1))::value;
694 !is_constructible_with_double_brace<std::tuple<int, int, int>,
int,
int,
int>(),
"");
695 static_assert(is_constructible_with_double_brace<std::array<int, 3>,
int,
int,
int>(),
699 template <
size_t I,
typename T,
700 typename R = decltype(std::declval<T &>().
template vc_get_<I>())>
701 R get_dispatcher(T &x,
void * =
nullptr)
703 return x.template vc_get_<I>();
705 template <
size_t I,
typename T,
706 typename R = decltype(std::declval<const T &>().
template vc_get_<I>())>
707 R get_dispatcher(
const T &x,
void * =
nullptr)
709 return x.template vc_get_<I>();
711 template <
size_t I,
typename T,
typename R = decltype(std::get<I>(std::declval<T &>()))>
712 R get_dispatcher(T &x,
int = 0)
714 return std::get<I>(x);
716 template <
size_t I,
typename T,
717 typename R = decltype(std::get<I>(std::declval<const T &>()))>
718 R get_dispatcher(
const T &x,
int = 0)
720 return std::get<I>(x);
725 template <
typename Scalar,
typename Base,
size_t N>
class Adapter :
public Base
729 template <std::size_t... Indexes,
typename T>
730 Adapter(Vc::index_sequence<Indexes...>,
const Scalar &x_, T, std::true_type)
731 : Base{{get_dispatcher<Indexes>(x_)...}}
736 template <std::size_t... Indexes>
737 Adapter(Vc::index_sequence<Indexes...>,
const Scalar &x_, std::true_type,
739 : Base{get_dispatcher<Indexes>(x_)...}
744 template <std::size_t... Indexes>
745 Adapter(Vc::index_sequence<Indexes...>,
const Scalar &x_, std::false_type,
747 : Base(get_dispatcher<Indexes>(x_)...)
751 template <std::size_t... Indexes>
752 Adapter(Vc::index_sequence<Indexes...> seq_,
const Scalar &x_)
754 std::integral_constant<
755 bool, is_constructible_with_single_brace<
756 Base, decltype(get_dispatcher<Indexes>(
757 std::declval<const Scalar &>()))...>()>(),
758 std::integral_constant<
759 bool, is_constructible_with_double_brace<
760 Base, decltype(get_dispatcher<Indexes>(
761 std::declval<const Scalar &>()))...>()>())
767 static constexpr
size_t size() {
return N; }
770 using base_type = Base;
773 using scalar_type = Scalar;
780 #if defined Vc_CLANG && Vc_CLANG < 0x30700
781 Vc_INTRINSIC Adapter(
const Adapter &x) : Base(x) {}
783 Adapter(
const Adapter &) =
default;
785 Adapter(Adapter &&) =
default;
788 Adapter &operator=(
const Adapter &) =
default;
790 Adapter &operator=(Adapter &&) =
default;
793 template <
typename U,
size_t TupleSize = determine_tuple_size<Scalar>(),
794 typename Seq = Vc::make_index_sequence<TupleSize>,
795 typename = enable_if<std::is_convertible<U, Scalar>::value>>
797 : Adapter(Seq(), static_cast<const Scalar &>(x_))
802 template <
typename A0,
typename... Args,
803 typename =
typename std::enable_if<
804 !Traits::is_index_sequence<A0>::value &&
805 (
sizeof...(Args) > 0 || !std::is_convertible<A0, Scalar>::value)>::type>
806 Adapter(A0 &&arg0_, Args &&... arguments_)
807 : Base(
std::forward<A0>(arg0_),
std::forward<Args>(arguments_)...)
812 template <
typename T,
813 typename = decltype(Base(std::declval<
const std::initializer_list<T> &>()))>
814 Adapter(
const std::initializer_list<T> &l_)
821 void *
operator new(
size_t size)
823 return Vc::Common::aligned_malloc<alignof(Adapter)>(size);
825 void *
operator new(size_t,
void *p_) {
return p_; }
826 void *
operator new[](
size_t size)
828 return Vc::Common::aligned_malloc<alignof(Adapter)>(size);
830 void *
operator new[](size_t ,
void *p_) {
return p_; }
832 void operator delete(
void *,
void *) {}
834 void operator delete[](
void *,
void *) {}
841 template <
class... TTypes,
class... TTypesV,
class... UTypes,
class... UTypesV,
size_t N>
842 inline bool operator==(
843 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
844 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) =
delete;
845 template <
class... TTypes,
class... TTypesV,
class... UTypes,
class... UTypesV,
size_t N>
846 inline bool operator!=(
847 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
848 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) =
delete;
849 template <
class... TTypes,
class... TTypesV,
class... UTypes,
class... UTypesV,
size_t N>
850 inline bool operator<=(
851 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
852 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) =
delete;
853 template <
class... TTypes,
class... TTypesV,
class... UTypes,
class... UTypesV,
size_t N>
854 inline bool operator>=(
855 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
856 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) =
delete;
857 template <
class... TTypes,
class... TTypesV,
class... UTypes,
class... UTypesV,
size_t N>
858 inline bool operator<(
859 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
860 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) =
delete;
861 template <
class... TTypes,
class... TTypesV,
class... UTypes,
class... UTypesV,
size_t N>
862 inline bool operator>(
863 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
864 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) =
delete;
875 template <
typename Scalar,
typename Base,
size_t N>
876 class tuple_size<
Vc::SimdizeDetail::Adapter<Scalar, Base, N>> :
public tuple_size<Base>
882 template <
size_t I,
typename Scalar,
typename Base,
size_t N>
883 class tuple_element<I,
Vc::SimdizeDetail::Adapter<Scalar, Base, N>>
884 :
public tuple_element<I, Base>
894 template <
typename S,
typename T,
size_t N>
895 class allocator<
Vc::SimdizeDetail::Adapter<S, T, N>>
899 template <
typename U>
struct rebind
901 typedef std::allocator<U> other;
906 namespace Vc_VERSIONED_NAMESPACE
908 namespace SimdizeDetail
918 template <
typename T>
static inline T decay_workaround(
const T &x) {
return x; }
923 template <
typename S,
typename T,
size_t N,
size_t... Indexes>
924 inline void assign_impl(Adapter<S, T, N> &a,
size_t i,
const S &x,
925 Vc::index_sequence<Indexes...>)
927 const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(x)))...> tmp(
928 decay_workaround(get_dispatcher<Indexes>(x))...);
929 auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(tmp), 0)...};
930 if (&unused == &unused) {}
937 template <
typename S,
typename T,
size_t N>
938 inline void assign(Adapter<S, T, N> &a,
size_t i,
const S &x)
940 assign_impl(a, i, x, Vc::make_index_sequence<determine_tuple_size<T>()>());
945 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
946 Vc_INTRINSIC
void assign(V &v,
size_t i,
typename V::EntryType x)
954 template <
typename S,
typename T,
size_t N,
size_t... Indexes>
955 inline S extract_impl(
const Adapter<S, T, N> &a,
size_t i, Vc::index_sequence<Indexes...>)
957 const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[i]))...> tmp(
958 decay_workaround(get_dispatcher<Indexes>(a)[i])...);
959 return S(get_dispatcher<Indexes>(tmp)...);
966 template <
typename S,
typename T,
size_t N>
967 inline S
extract(
const Adapter<S, T, N> &a,
size_t i)
969 return extract_impl(a, i, Vc::make_index_sequence<determine_tuple_size<S>()>());
974 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
975 Vc_INTRINSIC
typename V::EntryType extract(
const V &v,
size_t i)
980 template <
typename S,
typename T, std::size_t N, std::size_t... Indexes>
981 inline Adapter<S, T, N> shifted_impl(
const Adapter<S, T, N> &a,
int shift,
982 Vc::index_sequence<Indexes...>)
985 auto &&unused = {(get_dispatcher<Indexes>(r) = get_dispatcher<Indexes>(a).shifted(shift), 0)...};
986 if (&unused == &unused) {}
998 template <
typename S,
typename T,
size_t N>
999 inline Adapter<S, T, N>
shifted(
const Adapter<S, T, N> &a,
int shift)
1001 return shifted_impl(a, shift, Vc::make_index_sequence<determine_tuple_size<T>()>());
1007 template <
typename S,
typename T, std::size_t N, std::size_t... Indexes>
1008 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, S &x,
1009 Vc::index_sequence<Indexes...>)
1011 const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[0]))...> tmp{
1012 decay_workaround(get_dispatcher<Indexes>(a)[i])...};
1013 auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(x), 0)...};
1014 auto &&unused2 = {(get_dispatcher<Indexes>(x) = get_dispatcher<Indexes>(tmp), 0)...};
1015 if (&unused == &unused2) {}
1017 template <
typename S,
typename T, std::size_t N, std::size_t... Indexes>
1018 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b,
1019 std::size_t j, Vc::index_sequence<Indexes...>)
1021 const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[0]))...> tmp{
1022 decay_workaround(get_dispatcher<Indexes>(a)[i])...};
1023 auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(b)[j], 0)...};
1024 auto &&unused2 = {(get_dispatcher<Indexes>(b)[j] = get_dispatcher<Indexes>(tmp), 0)...};
1025 if (&unused == &unused2) {}
1032 template <
typename S,
typename T, std::
size_t N>
1033 inline void swap(Adapter<S, T, N> &a, std::size_t i, S &x)
1035 swap_impl(a, i, x, Vc::make_index_sequence<determine_tuple_size<T>()>());
1037 template <
typename S,
typename T, std::
size_t N>
1038 inline void swap(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b, std::size_t j)
1040 swap_impl(a, i, b, j, Vc::make_index_sequence<determine_tuple_size<T>()>());
1043 template <
typename A>
class Scalar
1045 using reference =
typename std::add_lvalue_reference<A>::type;
1046 using S =
typename A::scalar_type;
1047 using IndexSeq = Vc::make_index_sequence<determine_tuple_size<S>()>;
1050 Scalar(reference aa,
size_t ii) : a(aa), i(ii) {}
1053 Scalar(
const Scalar &) =
delete;
1054 Scalar(Scalar &&) =
delete;
1055 Scalar &operator=(
const Scalar &) =
delete;
1056 Scalar &operator=(Scalar &&) =
delete;
1058 void operator=(
const S &x) { assign_impl(a, i, x, IndexSeq()); }
1059 operator S()
const {
return extract_impl(a, i, IndexSeq()); }
1061 template <
typename AA>
1062 friend inline void swap(Scalar<AA> &&a,
typename AA::scalar_type &b);
1063 template <
typename AA>
1064 friend inline void swap(
typename AA::scalar_type &b, Scalar<AA> &&a);
1065 template <
typename AA>
friend inline void swap(Scalar<AA> &&a, Scalar<AA> &&b);
1074 template <
typename A>
inline void swap(Scalar<A> &&a,
typename A::scalar_type &b)
1076 swap_impl(a.a, a.i, b,
typename Scalar<A>::IndexSeq());
1080 template <
typename A>
inline void swap(
typename A::scalar_type &b, Scalar<A> &&a)
1082 swap_impl(a.a, a.i, b,
typename Scalar<A>::IndexSeq());
1085 template <
typename A>
inline void swap(Scalar<A> &&a, Scalar<A> &&b)
1087 swap_impl(a.a, a.i, b.a, b.i,
typename Scalar<A>::IndexSeq());
1090 template <
typename A>
class Interface
1092 using reference =
typename std::add_lvalue_reference<A>::type;
1094 Vc::make_index_sequence<determine_tuple_size<typename A::scalar_type>()>;
1097 Interface(reference aa) : a(aa) {}
1099 Scalar<A> operator[](
size_t i)
1103 typename A::scalar_type operator[](
size_t i)
const
1105 return extract_impl(a, i, IndexSeq());
1110 return shifted_impl(a, amount, IndexSeq());
1117 template <
typename S,
typename T,
size_t N>
1118 Interface<Adapter<S, T, N>> decorate(Adapter<S, T, N> &a)
1122 template <
typename S,
typename T,
size_t N>
1123 const Interface<const Adapter<S, T, N>> decorate(
const Adapter<S, T, N> &a)
1128 namespace IteratorDetails
1130 enum class Mutable { Yes, No };
1132 template <
typename It,
typename V,
size_t I,
size_t End>
1133 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I == End), It>)
1137 template <
typename It,
typename V,
size_t I,
size_t End>
1138 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I < End), It> it)
1140 V r = fromIteratorImpl<It, V, I + 1, End>(it);
1141 Traits::decay<decltype(get_dispatcher<I>(r))> tmp;
1142 for (
size_t j = 0; j < V::size(); ++j, ++it) {
1143 tmp[j] = get_dispatcher<I>(*it);
1145 get_dispatcher<I>(r) = tmp;
1148 template <
typename It,
typename V>
1149 Vc_INTRINSIC V fromIterator(enable_if<!Traits::is_simd_vector<V>::value,
const It &> it)
1151 return fromIteratorImpl<It, V, 0, determine_tuple_size<V>()>(it);
1153 template <
typename It,
typename V>
1154 Vc_INTRINSIC V fromIterator(enable_if<Traits::is_simd_vector<V>::value, It> it)
1157 for (
size_t j = 0; j < V::size(); ++j, ++it) {
1166 template <
typename T,
typename value_vector, Mutable>
class Pointer;
1176 template <
typename T,
typename value_vector>
class Pointer<T, value_vector, Mutable::Yes>
1178 static constexpr
auto Size = value_vector::size();
1182 value_vector *operator->() {
return &data; }
1189 Pointer(
const Pointer &) =
delete;
1190 Pointer &operator=(
const Pointer &) =
delete;
1191 Pointer &operator=(Pointer &&) =
delete;
1194 Pointer(Pointer &&) =
default;
1204 for (
size_t i = 0; i < Size; ++i, ++begin_iterator) {
1205 *begin_iterator =
extract(data, i);
1210 Pointer(
const T &it) : data(fromIterator<T, value_vector>(it)), begin_iterator(it) {}
1223 template <
typename T,
typename value_vector>
class Pointer<T, value_vector, Mutable::No>
1225 static constexpr
auto Size = value_vector::size();
1228 const value_vector *operator->()
const {
return &data; }
1231 Pointer(
const Pointer &) =
delete;
1232 Pointer &operator=(
const Pointer &) =
delete;
1233 Pointer &operator=(Pointer &&) =
delete;
1235 Pointer(Pointer &&) =
default;
1237 Pointer(
const T &it) : data(fromIterator<T, value_vector>(it)) {}
1255 template <
typename T,
typename value_vector, Mutable M>
class Reference;
1258 template <
typename T,
typename value_vector>
1259 class Reference<T, value_vector, Mutable::Yes> :
public value_vector
1261 static constexpr
auto Size = value_vector::size();
1263 using reference =
typename std::add_lvalue_reference<T>::type;
1264 reference scalar_it;
1269 Reference(reference first_it)
1270 : value_vector(fromIterator<T, value_vector>(first_it)), scalar_it(first_it)
1275 Reference(
const Reference &) =
delete;
1276 Reference(Reference &&) =
default;
1277 Reference &operator=(
const Reference &) =
delete;
1278 Reference &operator=(Reference &&) =
delete;
1285 void operator=(
const value_vector &x)
1287 static_cast<value_vector &
>(*this) = x;
1288 auto it = scalar_it;
1289 for (
size_t i = 0; i < Size; ++i, ++it) {
1296 template <
typename T,
typename value_vector>
1297 class Reference<T, value_vector, Mutable::No> :
public value_vector
1299 static constexpr
auto Size = value_vector::size();
1302 Reference(
const T &it) : value_vector(fromIterator<T, value_vector>(it)) {}
1304 Reference(
const Reference &) =
delete;
1305 Reference(Reference &&) =
default;
1306 Reference &operator=(
const Reference &) =
delete;
1307 Reference &operator=(Reference &&) =
delete;
1310 void operator=(
const value_vector &x) =
delete;
1313 template <
typename T,
size_t N,
1314 IteratorDetails::Mutable M =
1315 (Traits::is_output_iterator<T>::value ? Mutable::Yes : Mutable::No),
1316 typename V = simdize<
typename std::iterator_traits<T>::value_type, N>,
1317 size_t Size = V::size(),
1318 typename =
typename std::iterator_traits<T>::iterator_category>
1321 template <
typename T,
size_t N, IteratorDetails::Mutable M,
typename V,
size_t Size>
1322 class Iterator<T, N, M, V, Size,
std::forward_iterator_tag>
1323 :
public std::iterator<typename std::iterator_traits<T>::iterator_category, V,
1324 typename std::iterator_traits<T>::difference_type,
1325 IteratorDetails::Pointer<T, V, M>,
1326 IteratorDetails::Reference<T, V, M>>
1329 using pointer = IteratorDetails::Pointer<T, V, M>;
1330 using reference = IteratorDetails::Reference<T, V, M>;
1331 using const_pointer = IteratorDetails::Pointer<T, V, IteratorDetails::Mutable::No>;
1332 using const_reference =
1333 IteratorDetails::Reference<T, V, IteratorDetails::Mutable::No>;
1336 static constexpr std::size_t size() {
return Size; }
1338 Iterator() =
default;
1346 Iterator(
const T &x) : scalar_it(x) {}
1350 Iterator(T &&x) : scalar_it(
std::move(x)) {}
1354 Iterator &operator=(
const T &x)
1362 Iterator &operator=(T &&x)
1364 scalar_it = std::move(x);
1369 Iterator(
const Iterator &) =
default;
1371 Iterator(Iterator &&) =
default;
1373 Iterator &operator=(
const Iterator &) =
default;
1375 Iterator &operator=(Iterator &&) =
default;
1378 Iterator &operator++()
1380 std::advance(scalar_it, Size);
1384 Iterator operator++(
int)
1386 Iterator copy(*
this);
1399 bool operator==(
const Iterator &rhs)
const
1402 for (
size_t i = 1; i < Size; ++i) {
1403 Vc_ASSERT((++it != rhs.scalar_it));
1405 return scalar_it == rhs.scalar_it;
1415 bool operator!=(
const Iterator &rhs)
const
1418 for (
size_t i = 1; i < Size; ++i) {
1419 Vc_ASSERT((++it != rhs.scalar_it));
1421 return scalar_it != rhs.scalar_it;
1424 pointer operator->() {
return scalar_it; }
1432 reference operator*() {
return scalar_it; }
1434 const_pointer operator->()
const {
return scalar_it; }
1443 const_reference operator*()
const {
return scalar_it; }
1458 operator const T &()
const {
return scalar_it; }
1468 template <
typename T,
size_t N, IteratorDetails::Mutable M,
typename V,
size_t Size>
1469 class Iterator<T, N, M, V, Size,
std::bidirectional_iterator_tag>
1470 :
public Iterator<T, N, M, V, Size, std::forward_iterator_tag>
1472 using Base = Iterator<T, N, M, V, Size, std::forward_iterator_tag>;
1475 using Base::scalar_it;
1478 using pointer =
typename Base::pointer;
1479 using reference =
typename Base::reference;
1480 using const_pointer =
typename Base::const_pointer;
1481 using const_reference =
typename Base::const_reference;
1483 using Iterator<T, N, M, V, Size,
1484 std::forward_iterator_tag>::Iterator;
1490 std::advance(scalar_it, -Size);
1496 Iterator copy(*
this);
1506 template <
typename T,
size_t N, IteratorDetails::Mutable M,
typename V,
size_t Size>
1507 class Iterator<T, N, M, V, Size,
std::random_access_iterator_tag>
1508 :
public Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1513 using Base::scalar_it;
1516 using pointer =
typename Base::pointer;
1517 using reference =
typename Base::reference;
1518 using const_pointer =
typename Base::const_pointer;
1519 using const_reference =
typename Base::const_reference;
1520 using difference_type =
typename std::iterator_traits<T>::difference_type;
1525 Iterator &operator+=(difference_type n)
1527 scalar_it += n * Size;
1530 Iterator operator+(difference_type n)
const {
return Iterator(*
this) += n; }
1532 Iterator &operator-=(difference_type n)
1534 scalar_it -= n * Size;
1537 Iterator operator-(difference_type n)
const {
return Iterator(*
this) -= n; }
1539 difference_type operator-(
const Iterator &rhs)
const
1541 constexpr difference_type n = Size;
1542 Vc_ASSERT((scalar_it - rhs.scalar_it) % n ==
1548 return (scalar_it - rhs.scalar_it) / n;
1557 return scalar_it + Size <= rhs.scalar_it;
1560 bool operator>(
const Iterator &rhs)
const
1562 return scalar_it >= rhs.scalar_it + Size;
1565 bool operator<=(
const Iterator &rhs)
const
1567 return scalar_it + (Size - 1) <= rhs.scalar_it;
1570 bool operator>=(
const Iterator &rhs)
const
1572 return scalar_it >= rhs.scalar_it + (Size - 1);
1575 reference operator[](difference_type i) {
return *(*
this + i); }
1576 const_reference operator[](difference_type i)
const {
return *(*
this + i); }
1579 template <
typename T,
size_t N, IteratorDetails::Mutable M,
typename V,
size_t Size>
1580 Iterator<T, N, M, V, Size, std::random_access_iterator_tag> operator+(
1581 typename Iterator<T, N, M, V, Size, std::random_access_iterator_tag>::difference_type
1583 const Iterator<T, N, M, V, Size, std::random_access_iterator_tag> &i)
1598 template <
typename T,
size_t N,
typename MT>
1599 struct ReplaceTypes<T, N, MT, Category::ForwardIterator>
1601 using type = IteratorDetails::Iterator<T, N>;
1603 template <
typename T,
size_t N,
typename MT>
1604 struct ReplaceTypes<T, N, MT, Category::BidirectionalIterator>
1606 using type = IteratorDetails::Iterator<T, N>;
1608 template <
typename T,
size_t N,
typename MT>
1609 struct ReplaceTypes<T, N, MT, Category::RandomAccessIterator>
1611 using type = IteratorDetails::Iterator<T, N>;
1617 template <Vc::Operator Op,
typename S,
typename T, std::size_t N,
typename M,
typename U,
1619 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size<S>() && M::size() == N),
void>
1620 conditional_assign(Adapter<S, T, N> &,
const M &,
const U &)
1623 template <Vc::Operator Op,
typename S,
typename T, std::size_t N,
typename M,
typename U,
1624 std::size_t Offset = 0>
1625 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size<S>() && M::size() == N),
void>
1626 conditional_assign(Adapter<S, T, N> &lhs,
const M &mask,
const U &rhs)
1628 using V =
typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1629 using M2 =
typename V::mask_type;
1630 conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask), get_dispatcher<Offset>(rhs));
1631 conditional_assign<Op, S, T, N, M, U, Offset + 1>(lhs, mask, rhs);
1633 template <Vc::Operator Op,
typename S,
typename T, std::size_t N,
typename M,
1635 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size<S>() && M::size() == N),
void>
1636 conditional_assign(Adapter<S, T, N> &,
const M &)
1639 template <Vc::Operator Op,
typename S,
typename T, std::size_t N,
typename M,
1640 std::size_t Offset = 0>
1641 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size<S>() && M::size() == N),
void>
1642 conditional_assign(Adapter<S, T, N> &lhs,
const M &mask)
1644 using V =
typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1645 using M2 =
typename V::mask_type;
1646 conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask));
1647 conditional_assign<Op, S, T, N, M, Offset + 1>(lhs, mask);
1671 template <
typename T,
size_t N = 0,
typename MT =
void>
1672 using simdize = SimdizeDetail::simdize<T, N, MT>;
1693 #define Vc_SIMDIZE_INTERFACE(MEMBERS_) \
1694 template <std::size_t N_> \
1695 inline auto vc_get_()->decltype(std::get<N_>(std::tie MEMBERS_)) \
1697 return std::get<N_>(std::tie MEMBERS_); \
1699 template <std::size_t N_> \
1700 inline auto vc_get_() const->decltype(std::get<N_>(std::tie MEMBERS_)) \
1702 return std::get<N_>(std::tie MEMBERS_); \
1704 enum : std::size_t { \
1705 tuple_size = std::tuple_size<decltype(std::tie MEMBERS_)>::value \
1712 using Vc::SimdizeDetail::swap;
1715 #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...