vc/godbolt/algorithm

1630 lines
56 KiB
Plaintext

#ifndef VC_COMMON_ALGORITHMS_H_
#define VC_COMMON_ALGORITHMS_H_
#ifndef VC_COMMON_SIMDIZE_H_
#define VC_COMMON_SIMDIZE_H_
#include <tuple>
#include <array>
#ifndef VC_ALLOCATOR_H_
#define VC_ALLOCATOR_H_
#include <new>
#include <cstddef>
#include <cstdlib>
#include <utility>
#ifdef Vc_MSVC
#define Vc_DECLARE_ALLOCATOR(Type) \
namespace std \
{ \
template <> class allocator<Type> : public ::Vc::Allocator<Type> \
{ \
public: \
template <typename U> struct rebind { \
typedef ::std::allocator<U> other; \
}; \
\
const allocator &select_on_container_copy_construction() const { return *this; } \
}; \
}
#else
#define Vc_DECLARE_ALLOCATOR(Type) \
namespace std \
{ \
template <> class allocator<Type> : public ::Vc::Allocator<Type> \
{ \
public: \
template <typename U> struct rebind { \
typedef ::std::allocator<U> other; \
}; \
}; \
}
#endif
namespace Vc_VERSIONED_NAMESPACE
{
using std::size_t;
using std::ptrdiff_t;
template<typename T> class Allocator
{
private:
enum Constants {
#ifdef Vc_HAVE_STD_MAX_ALIGN_T
NaturalAlignment = alignof(std::max_align_t),
#elif defined(Vc_HAVE_MAX_ALIGN_T)
NaturalAlignment = alignof(::max_align_t),
#else
NaturalAlignment = sizeof(void *) > alignof(long double) ? sizeof(void *) :
(alignof(long double) > alignof(long long) ? alignof(long double) : alignof(long long)),
#endif
#if defined Vc_IMPL_AVX
SimdAlignment = 32,
#elif defined Vc_IMPL_SSE
SimdAlignment = 16,
#else
SimdAlignment = 1,
#endif
Alignment = alignof(T) > SimdAlignment ? alignof(T) : SimdAlignment,
ExtraBytes = Alignment > NaturalAlignment ? Alignment : 0,
AlignmentMask = Alignment - 1
};
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
template<typename U> struct rebind { typedef Allocator<U> other; };
Allocator() throw() { }
Allocator(const Allocator&) throw() { }
template<typename U> Allocator(const Allocator<U>&) throw() { }
pointer address(reference x) const { return &x; }
const_pointer address(const_reference x) const { return &x; }
pointer allocate(size_type n, const void* = 0)
{
if (n > this->max_size()) {
throw std::bad_alloc();
}
char *p = static_cast<char *>(::operator new(n * sizeof(T) + ExtraBytes));
if (ExtraBytes > 0) {
char *const pp = p;
p += ExtraBytes;
const char *null = 0;
p -= ((p - null) & AlignmentMask);
reinterpret_cast<char **>(p)[-1] = pp;
}
return reinterpret_cast<pointer>(p);
}
void deallocate(pointer p, size_type)
{
if (ExtraBytes > 0) {
p = reinterpret_cast<pointer *>(p)[-1];
}
::operator delete(p);
}
size_type max_size() const throw() { return size_t(-1) / sizeof(T); }
#ifdef Vc_MSVC
const Allocator &select_on_container_copy_construction() const { return *this; }
void construct(pointer p) { ::new(p) T(); }
void construct(pointer p, const T& val) { ::new(p) T(val); }
void destroy(pointer p) { p->~T(); }
#else
template<typename U, typename... Args> void construct(U* p, Args&&... args)
{
::new(p) U(std::forward<Args>(args)...);
}
template<typename U> void destroy(U* p) { p->~U(); }
#endif
};
template<typename T> inline bool operator==(const Allocator<T>&, const Allocator<T>&) { return true; }
template<typename T> inline bool operator!=(const Allocator<T>&, const Allocator<T>&) { return false; }
}
namespace std
{
template<typename T, typename Abi>
class allocator<Vc::Vector<T, Abi> > : public ::Vc::Allocator<Vc::Vector<T, Abi> >
{
public:
template<typename U> struct rebind { typedef ::std::allocator<U> other; };
#ifdef Vc_MSVC
const allocator &select_on_container_copy_construction() const { return *this; }
#endif
};
template <typename T, typename Abi>
class allocator<Vc::Mask<T, Abi>> : public ::Vc::Allocator<Vc::Mask<T, Abi>>
{
public:
template<typename U> struct rebind { typedef ::std::allocator<U> other; };
#ifdef Vc_MSVC
const allocator &select_on_container_copy_construction() const { return *this; }
#endif
};
template <typename T, std::size_t N, typename V, std::size_t M>
class allocator<Vc::SimdArray<T, N, V, M>> : public ::Vc::Allocator<Vc::SimdArray<T, N, V, M>>
{
public:
template<typename U> struct rebind { typedef ::std::allocator<U> other; };
#ifdef Vc_MSVC
const allocator &select_on_container_copy_construction() const { return *this; }
#endif
};
template <typename T, std::size_t N, typename V, std::size_t M>
class allocator<Vc::SimdMaskArray<T, N, V, M>> : public ::Vc::Allocator<Vc::SimdMaskArray<T, N, V, M>>
{
public:
template<typename U> struct rebind { typedef ::std::allocator<U> other; };
#ifdef Vc_MSVC
const allocator &select_on_container_copy_construction() const { return *this; }
#endif
};
}
#endif
#ifndef VC_COMMON_INTERLEAVEDMEMORY_H_
#define VC_COMMON_INTERLEAVEDMEMORY_H_
namespace Vc_VERSIONED_NAMESPACE
{
namespace Common
{
template<typename V, typename I, bool Readonly> struct InterleavedMemoryAccessBase
{
typedef typename std::conditional<
Readonly, typename std::add_const<typename V::EntryType>::type,
typename V::EntryType>::type T;
typedef typename V::AsArg VArg;
typedef T Ta Vc_MAY_ALIAS;
const I m_indexes;
Ta *const m_data;
Vc_ALWAYS_INLINE InterleavedMemoryAccessBase(typename I::AsArg indexes, Ta *data)
: m_indexes(indexes), m_data(data)
{
}
template <typename... Vs> Vc_INTRINSIC void deinterleave(Vs &&... vs) const
{
Impl::deinterleave(m_data, m_indexes, std::forward<Vs>(vs)...);
}
protected:
using Impl = Vc::Detail::InterleaveImpl<V, V::Size, sizeof(V)>;
template <typename T, std::size_t... Indexes>
Vc_INTRINSIC void callInterleave(T &&a, index_sequence<Indexes...>)
{
Impl::interleave(m_data, m_indexes, a[Indexes]...);
}
};
template <size_t StructSize, typename V, typename I = typename V::IndexType,
bool Readonly>
struct InterleavedMemoryReadAccess : public InterleavedMemoryAccessBase<V, I, Readonly>
{
typedef InterleavedMemoryAccessBase<V, I, Readonly> Base;
typedef typename Base::Ta Ta;
Vc_ALWAYS_INLINE InterleavedMemoryReadAccess(Ta *data, typename I::AsArg indexes)
: Base(StructSize == 1u
? indexes
: StructSize == 2u
? indexes << 1
: StructSize == 4u
? indexes << 2
: StructSize == 8u
? indexes << 3
: StructSize == 16u ? indexes << 4
: indexes * I(int(StructSize)),
data)
{
}
template <typename T, std::size_t... Indexes>
Vc_ALWAYS_INLINE T deinterleave_unpack(index_sequence<Indexes...>) const
{
T r;
Base::Impl::deinterleave(this->m_data, this->m_indexes, std::get<Indexes>(r)...);
return r;
}
template <typename T,
typename = enable_if<(std::is_default_constructible<T>::value &&
std::is_same<V, Traits::decay<decltype(std::get<0>(
std::declval<T &>()))>>::value)>>
Vc_ALWAYS_INLINE operator T() const
{
return deinterleave_unpack<T>(make_index_sequence<std::tuple_size<T>::value>());
}
};
template<typename I> struct CheckIndexesUnique
{
#ifdef NDEBUG
static Vc_INTRINSIC void test(const I &) {}
#else
static void test(const I &indexes)
{
const I test = indexes.sorted();
Vc_ASSERT(I::Size == 1 || (test == test.rotated(1)).isEmpty())
}
#endif
};
template<size_t S> struct CheckIndexesUnique<SuccessiveEntries<S> >
{
static Vc_INTRINSIC void test(const SuccessiveEntries<S> &) {}
};
template <size_t StructSize, typename V, typename I = typename V::IndexType>
struct InterleavedMemoryAccess : public InterleavedMemoryReadAccess<StructSize, V, I, false>
{
typedef InterleavedMemoryAccessBase<V, I, false> Base;
typedef typename Base::Ta Ta;
Vc_ALWAYS_INLINE InterleavedMemoryAccess(Ta *data, typename I::AsArg indexes)
: InterleavedMemoryReadAccess<StructSize, V, I, false>(data, indexes)
{
CheckIndexesUnique<I>::test(indexes);
}
template <int N> Vc_ALWAYS_INLINE void operator=(VectorReferenceArray<N, V> &&rhs)
{
static_assert(N <= StructSize,
"You_are_trying_to_scatter_more_data_into_the_struct_than_it_has");
this->callInterleave(std::move(rhs), make_index_sequence<N>());
}
template <int N> Vc_ALWAYS_INLINE void operator=(VectorReferenceArray<N, const V> &&rhs)
{
static_assert(N <= StructSize,
"You_are_trying_to_scatter_more_data_into_the_struct_than_it_has");
this->callInterleave(std::move(rhs), make_index_sequence<N>());
}
};
template<typename S, typename V> class InterleavedMemoryWrapper
{
typedef typename std::conditional<std::is_const<S>::value,
const typename V::EntryType,
typename V::EntryType>::type T;
typedef typename V::IndexType I;
typedef typename V::AsArg VArg;
typedef const I &IndexType;
static constexpr std::size_t StructSize = sizeof(S) / sizeof(T);
using ReadAccess = InterleavedMemoryReadAccess<StructSize, V>;
using Access =
typename std::conditional<std::is_const<T>::value, ReadAccess,
InterleavedMemoryAccess<StructSize, V>>::type;
using ReadSuccessiveEntries =
InterleavedMemoryReadAccess<StructSize, V, SuccessiveEntries<StructSize>>;
using AccessSuccessiveEntries = typename std::conditional<
std::is_const<T>::value, ReadSuccessiveEntries,
InterleavedMemoryAccess<StructSize, V, SuccessiveEntries<StructSize>>>::type;
typedef T Ta Vc_MAY_ALIAS;
Ta *const m_data;
static_assert(StructSize * sizeof(T) == sizeof(S),
"InterleavedMemoryAccess_does_not_support_packed_structs");
public:
Vc_ALWAYS_INLINE InterleavedMemoryWrapper(S *s)
: m_data(reinterpret_cast<Ta *>(s))
{
}
template <typename IT>
Vc_ALWAYS_INLINE enable_if<!std::is_convertible<IT, size_t>::value &&
std::is_convertible<IT, IndexType>::value &&
!std::is_const<S>::value,
Access>
operator[](IT indexes)
{
return Access(m_data, indexes);
}
Vc_ALWAYS_INLINE ReadAccess operator[](IndexType indexes) const
{
return ReadAccess(m_data, indexes);
}
Vc_ALWAYS_INLINE ReadAccess gather(IndexType indexes) const { return operator[](indexes); }
Vc_ALWAYS_INLINE ReadSuccessiveEntries operator[](size_t first) const
{
return ReadSuccessiveEntries(m_data, first);
}
Vc_ALWAYS_INLINE AccessSuccessiveEntries operator[](size_t first)
{
return AccessSuccessiveEntries(m_data, first);
}
};
}
using Common::InterleavedMemoryWrapper;
template <typename V, typename S>
inline Common::InterleavedMemoryWrapper<S, V> make_interleave_wrapper(S *s)
{
return Common::InterleavedMemoryWrapper<S, V>(s);
}
}
#endif
namespace Vc_VERSIONED_NAMESPACE
{
namespace SimdizeDetail
{
using std::is_same;
using std::is_base_of;
using std::false_type;
using std::true_type;
using std::iterator_traits;
using std::conditional;
using std::size_t;
template <typename... Ts> struct Typelist;
enum class Category {
None,
ArithmeticVectorizable,
InputIterator,
OutputIterator,
ForwardIterator,
BidirectionalIterator,
RandomAccessIterator,
ClassTemplate
};
template <typename T, typename ItCat = typename T::iterator_category>
constexpr Category iteratorCategories(int, ItCat * = nullptr)
{
return is_base_of<std::random_access_iterator_tag, ItCat>::value
? Category::RandomAccessIterator
: is_base_of<std::bidirectional_iterator_tag, ItCat>::value
? Category::BidirectionalIterator
: is_base_of<std::forward_iterator_tag, ItCat>::value
? Category::ForwardIterator
: is_base_of<std::output_iterator_tag, ItCat>::value
? Category::OutputIterator
: is_base_of<std::input_iterator_tag, ItCat>::value
? Category::InputIterator
: Category::None;
}
template <typename T>
constexpr enable_if<std::is_pointer<T>::value, Category> iteratorCategories(float)
{
return Category::RandomAccessIterator;
}
template <typename T> constexpr Category iteratorCategories(...)
{
return Category::None;
}
template <typename T> struct is_class_template : public false_type
{
};
template <template <typename...> class C, typename... Ts>
struct is_class_template<C<Ts...>> : public true_type
{
};
template <typename T> constexpr Category typeCategory()
{
return (is_same<T, bool>::value || is_same<T, short>::value ||
is_same<T, unsigned short>::value || is_same<T, int>::value ||
is_same<T, unsigned int>::value || is_same<T, float>::value ||
is_same<T, double>::value)
? Category::ArithmeticVectorizable
: iteratorCategories<T>(int()) != Category::None
? iteratorCategories<T>(int())
: is_class_template<T>::value ? Category::ClassTemplate
: Category::None;
}
template <typename T, size_t TupleSize = std::tuple_size<T>::value>
constexpr size_t determine_tuple_size()
{
return TupleSize;
}
template <typename T, size_t TupleSize = T::tuple_size>
constexpr size_t determine_tuple_size(size_t = T::tuple_size)
{
return TupleSize;
}
template <typename T> struct determine_tuple_size_
: public std::integral_constant<size_t, determine_tuple_size<T>()>
{};
namespace
{
template <typename T> struct The_simdization_for_the_requested_type_is_not_implemented;
}
template <typename T, size_t N, typename MT, Category = typeCategory<T>()>
struct ReplaceTypes : public The_simdization_for_the_requested_type_is_not_implemented<T>
{
};
template <typename T, size_t N, typename MT> struct ReplaceTypes<T, N, MT, Category::None>
{
typedef T type;
};
template <typename T, size_t N = 0, typename MT = void>
using simdize = typename SimdizeDetail::ReplaceTypes<T, N, MT>::type;
template <class T, size_t N,
class Best = typename Common::select_best_vector_type<T, N>::type>
using deduce_vector_t =
typename std::conditional<Best::size() == N, Best, SimdArray<T, N>>::type;
template <typename T, size_t N, typename MT>
struct ReplaceTypes<T, N, MT, Category::ArithmeticVectorizable>
: public conditional<N == 0, Vector<T>, deduce_vector_t<T, N>> {
};
template <size_t N, typename MT>
struct ReplaceTypes<bool, N, MT, Category::ArithmeticVectorizable>
: public std::enable_if<true, typename ReplaceTypes<MT, N, MT>::type::mask_type> {
};
template <size_t N>
struct ReplaceTypes<bool, N, void, Category::ArithmeticVectorizable>
: public ReplaceTypes<bool, N, float, Category::ArithmeticVectorizable>
{
};
template <size_t N, typename MT, typename Replaced, typename... Remaining>
struct SubstituteOneByOne;
template <size_t N, typename MT, typename... Replaced, typename T,
typename... Remaining>
struct SubstituteOneByOne<N, MT, Typelist<Replaced...>, T, Remaining...>
{
private:
template <typename U, size_t M = U::Size>
static std::integral_constant<size_t, M> size_or_0(int);
template <typename U> static std::integral_constant<size_t, 0> size_or_0(...);
using V = simdize<T, N, MT>;
static constexpr auto NewN = N != 0 ? N : decltype(size_or_0<V>(int()))::value;
typedef conditional_t<(N != NewN && is_same<MT, void>::value),
conditional_t<is_same<T, bool>::value, float, T>, MT> NewMT;
public:
using type = typename SubstituteOneByOne<NewN, NewMT, Typelist<Replaced..., V>,
Remaining...>::type;
};
template <size_t Size, typename... Replaced> struct SubstitutedBase;
template <typename Replaced> struct SubstitutedBase<1, Replaced> {
template <typename ValueT, template <typename, ValueT...> class C, ValueT... Values>
using SubstitutedWithValues = C<Replaced, Values...>;
};
template <typename R0, typename R1> struct SubstitutedBase<2, R0, R1>
{
template <typename ValueT, template <typename, typename, ValueT...> class C,
ValueT... Values>
using SubstitutedWithValues = C<R0, R1, Values...>;
};
template <typename R0, typename R1, typename R2> struct SubstitutedBase<3, R0, R1, R2>
{
template <typename ValueT, template <typename, typename, typename, ValueT...> class C,
ValueT... Values>
using SubstitutedWithValues = C<R0, R1, R2, Values...>;
};
#if defined Vc_ICC || defined Vc_MSVC
#define Vc_VALUE_PACK_EXPANSION_IS_BROKEN 1
#endif
template <typename... Replaced> struct SubstitutedBase<4, Replaced...> {
#ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
template <typename ValueT,
template <typename, typename, typename, typename, ValueT...> class C,
ValueT... Values>
using SubstitutedWithValues = C<Replaced..., Values...>;
#endif
};
template <typename... Replaced> struct SubstitutedBase<5, Replaced...> {
#ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
template <typename ValueT, template <typename, typename, typename, typename, typename,
ValueT...> class C,
ValueT... Values>
using SubstitutedWithValues = C<Replaced..., Values...>;
#endif
};
template <typename... Replaced> struct SubstitutedBase<6, Replaced...> {
#ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
template <typename ValueT, template <typename, typename, typename, typename, typename,
typename, ValueT...> class C,
ValueT... Values>
using SubstitutedWithValues = C<Replaced..., Values...>;
#endif
};
template <typename... Replaced> struct SubstitutedBase<7, Replaced...> {
#ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
template <typename ValueT, template <typename, typename, typename, typename, typename,
typename, typename, ValueT...> class C,
ValueT... Values>
using SubstitutedWithValues = C<Replaced..., Values...>;
#endif
};
template <typename... Replaced> struct SubstitutedBase<8, Replaced...> {
#ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
template <typename ValueT, template <typename, typename, typename, typename, typename,
typename, typename, typename, ValueT...> class C,
ValueT... Values>
using SubstitutedWithValues = C<Replaced..., Values...>;
#endif
};
template <size_t N_, typename MT, typename Replaced0, typename... Replaced>
struct SubstituteOneByOne<N_, MT, Typelist<Replaced0, Replaced...>>
{
struct type
: public SubstitutedBase<sizeof...(Replaced) + 1, Replaced0, Replaced...> {
static constexpr auto N = N_;
template <template <typename...> class C>
using Substituted = C<Replaced0, Replaced...>;
};
};
template <typename Scalar, typename Base, size_t N> class Adapter;
template <template <typename...> class C, typename... Ts, size_t N, typename MT>
struct ReplaceTypes<C<Ts...>, N, MT, Category::ClassTemplate>
{
using SubstitutionResult =
typename SubstituteOneByOne<N, MT, Typelist<>, Ts...>::type;
using Vectorized = typename SubstitutionResult::template Substituted<C>;
using type = conditional_t<is_same<C<Ts...>, Vectorized>::value, C<Ts...>,
Adapter<C<Ts...>, Vectorized, SubstitutionResult::N>>;
};
#ifdef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
#define Vc_DEFINE_NONTYPE_REPLACETYPES_(ValueType_) \
template <template <typename, ValueType_...> class C, typename T, ValueType_ Value0, \
ValueType_... Values> \
struct is_class_template<C<T, Value0, Values...>> : public true_type { \
}; \
template <template <typename, typename, ValueType_...> class C, typename T0, \
typename T1, ValueType_ Value0, ValueType_... Values> \
struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type { \
}; \
template <template <typename, typename, typename, ValueType_...> class C, \
typename T0, typename T1, typename T2, ValueType_ Value0, \
ValueType_... Values> \
struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type { \
}; \
template <template <typename, typename, typename, typename, ValueType_...> class C, \
typename T0, typename T1, typename T2, typename T3, ValueType_ Value0, \
ValueType_... Values> \
struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type { \
}; \
template <template <typename, typename, typename, typename, typename, ValueType_...> \
class C, \
typename T0, typename T1, typename T2, typename T3, typename T4, \
ValueType_ Value0, ValueType_... Values> \
struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
: public true_type { \
}; \
template <template <typename, typename, typename, typename, typename, typename, \
ValueType_...> class C, \
typename T0, typename T1, typename T2, typename T3, typename T4, \
typename T5, ValueType_ Value0, ValueType_... Values> \
struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
: public true_type { \
}; \
template <template <typename, typename, typename, typename, typename, typename, \
typename, ValueType_...> class C, \
typename T0, typename T1, typename T2, typename T3, typename T4, \
typename T5, typename T6, ValueType_ Value0, ValueType_... Values> \
struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
: public true_type { \
}; \
template <template <typename, ValueType_> class C, typename T0, ValueType_ Value0, \
size_t N, typename MT> \
struct ReplaceTypes<C<T0, Value0>, N, MT, Category::ClassTemplate> { \
typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
Substituted; \
static constexpr auto NN = tmp::N; \
typedef conditional_t<is_same<C<T0, Value0>, Substituted>::value, C<T0, Value0>, \
Adapter<C<T0, Value0>, Substituted, NN>> type; \
}; \
template <template <typename, typename, ValueType_> class C, typename T0, \
typename T1, ValueType_ Value0, size_t N, typename MT> \
struct ReplaceTypes<C<T0, T1, Value0>, N, MT, Category::ClassTemplate> { \
typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
Substituted; \
static constexpr auto NN = tmp::N; \
typedef conditional_t<is_same<C<T0, T1, Value0>, Substituted>::value, \
C<T0, T1, Value0>, \
Adapter<C<T0, T1, Value0>, Substituted, NN>> type; \
}; \
template <template <typename, typename, typename, ValueType_> class C, typename T0, \
typename T1, typename T2, ValueType_ Value0, size_t N, typename MT> \
struct ReplaceTypes<C<T0, T1, T2, Value0>, N, MT, Category::ClassTemplate> { \
typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
Substituted; \
static constexpr auto NN = tmp::N; \
typedef conditional_t<is_same<C<T0, T1, T2, Value0>, Substituted>::value, \
C<T0, T1, T2, Value0>, \
Adapter<C<T0, T1, T2, Value0>, Substituted, NN>> type; \
}
#else
#define Vc_DEFINE_NONTYPE_REPLACETYPES_(ValueType_) \
template <template <typename, ValueType_...> class C, typename T, ValueType_ Value0, \
ValueType_... Values> \
struct is_class_template<C<T, Value0, Values...>> : public true_type { \
}; \
template <template <typename, typename, ValueType_...> class C, typename T0, \
typename T1, ValueType_ Value0, ValueType_... Values> \
struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type { \
}; \
template <template <typename, typename, typename, ValueType_...> class C, \
typename T0, typename T1, typename T2, ValueType_ Value0, \
ValueType_... Values> \
struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type { \
}; \
template <template <typename, typename, typename, typename, ValueType_...> class C, \
typename T0, typename T1, typename T2, typename T3, ValueType_ Value0, \
ValueType_... Values> \
struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type { \
}; \
template <template <typename, typename, typename, typename, typename, ValueType_...> \
class C, \
typename T0, typename T1, typename T2, typename T3, typename T4, \
ValueType_ Value0, ValueType_... Values> \
struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
: public true_type { \
}; \
template <template <typename, typename, typename, typename, typename, typename, \
ValueType_...> class C, \
typename T0, typename T1, typename T2, typename T3, typename T4, \
typename T5, ValueType_ Value0, ValueType_... Values> \
struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
: public true_type { \
}; \
template <template <typename, typename, typename, typename, typename, typename, \
typename, ValueType_...> class C, \
typename T0, typename T1, typename T2, typename T3, typename T4, \
typename T5, typename T6, ValueType_ Value0, ValueType_... Values> \
struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
: public true_type { \
}; \
template <template <typename, ValueType_...> class C, typename T0, \
ValueType_ Value0, ValueType_... Values, size_t N, typename MT> \
struct ReplaceTypes<C<T0, Value0, Values...>, N, MT, Category::ClassTemplate> { \
typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
Values...> Substituted; \
static constexpr auto NN = tmp::N; \
typedef conditional_t<is_same<C<T0, Value0, Values...>, Substituted>::value, \
C<T0, Value0, Values...>, \
Adapter<C<T0, Value0, Values...>, Substituted, NN>> type; \
}; \
template <template <typename, typename, ValueType_...> class C, typename T0, \
typename T1, ValueType_ Value0, ValueType_... Values, size_t N, \
typename MT> \
struct ReplaceTypes<C<T0, T1, Value0, Values...>, N, MT, Category::ClassTemplate> { \
typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
Values...> Substituted; \
static constexpr auto NN = tmp::N; \
typedef conditional_t<is_same<C<T0, T1, Value0, Values...>, Substituted>::value, \
C<T0, T1, Value0, Values...>, \
Adapter<C<T0, T1, Value0, Values...>, Substituted, NN>> \
type; \
}; \
template <template <typename, typename, typename, ValueType_...> class C, \
typename T0, typename T1, typename T2, ValueType_ Value0, \
ValueType_... Values, size_t N, typename MT> \
struct ReplaceTypes<C<T0, T1, T2, Value0, Values...>, N, MT, \
Category::ClassTemplate> { \
typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
Values...> Substituted; \
static constexpr auto NN = tmp::N; \
typedef conditional_t< \
is_same<C<T0, T1, T2, Value0, Values...>, Substituted>::value, \
C<T0, T1, T2, Value0, Values...>, \
Adapter<C<T0, T1, T2, Value0, Values...>, Substituted, NN>> type; \
}
#endif
Vc_DEFINE_NONTYPE_REPLACETYPES_(bool);
Vc_DEFINE_NONTYPE_REPLACETYPES_(wchar_t);
Vc_DEFINE_NONTYPE_REPLACETYPES_(char);
Vc_DEFINE_NONTYPE_REPLACETYPES_( signed char);
Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned char);
Vc_DEFINE_NONTYPE_REPLACETYPES_( signed short);
Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned short);
Vc_DEFINE_NONTYPE_REPLACETYPES_( signed int);
Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned int);
Vc_DEFINE_NONTYPE_REPLACETYPES_( signed long);
Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned long);
Vc_DEFINE_NONTYPE_REPLACETYPES_( signed long long);
Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned long long);
#undef Vc_DEFINE_NONTYPE_REPLACETYPES_
namespace preferred_construction_impl
{
template <typename T> T create();
template <class Type, class... Init, class = decltype(Type(create<Init>()...))>
constexpr std::integral_constant<int, 0> test(int);
template <class Type, class... Init, class = decltype(Type{create<Init>()...})>
constexpr std::integral_constant<int, 1> test(float);
template <class Type, class... Init, class T, class = decltype(Type{{create<Init>()...}})>
constexpr std::integral_constant<int, 2> test(T);
template <class Type, class... Init> constexpr std::integral_constant<int, 3> test(...);
}
template <class Type, class... Init>
constexpr inline decltype(preferred_construction_impl::test<Type, Init...>(0))
preferred_construction()
{
return {};
}
template <size_t I, typename T,
typename R = decltype(std::declval<T &>().template vc_get_<I>())>
R get_dispatcher(T &x, void * = nullptr)
{
return x.template vc_get_<I>();
}
template <size_t I, typename T,
typename R = decltype(std::declval<const T &>().template vc_get_<I>())>
R get_dispatcher(const T &x, void * = nullptr)
{
return x.template vc_get_<I>();
}
template <size_t I, typename T, typename R = decltype(std::get<I>(std::declval<T &>()))>
R get_dispatcher(T &x, int = 0)
{
return std::get<I>(x);
}
template <size_t I, typename T,
typename R = decltype(std::get<I>(std::declval<const T &>()))>
R get_dispatcher(const T &x, int = 0)
{
return std::get<I>(x);
}
template <size_t I, class T, class = void>
struct my_tuple_element : std::tuple_element<I, T> {
};
template <size_t I, class T>
struct my_tuple_element<
I, T, typename std::conditional<
true, void, decltype(std::declval<T>().template vc_get_<I>())>::type> {
using type =
typename std::decay<decltype(std::declval<T>().template vc_get_<I>())>::type;
};
template <class... Ts> struct homogeneous_sizeof;
template <class T, class = void> struct homogeneous_sizeof_one;
template <class T>
struct homogeneous_sizeof_one<T,
typename std::enable_if<std::is_arithmetic<T>::value>::type>
: std::integral_constant<size_t, sizeof(T)> {
};
template <class T0> struct homogeneous_sizeof<T0> : homogeneous_sizeof_one<T0> {
};
template <class T0, class... Ts>
struct homogeneous_sizeof<T0, Ts...>
: std::integral_constant<size_t, homogeneous_sizeof<T0>::value ==
homogeneous_sizeof<Ts...>::value
? homogeneous_sizeof<T0>::value
: 0> {
};
template <class T, size_t... Is>
std::integral_constant<
size_t, homogeneous_sizeof<typename my_tuple_element<Is, T>::type...>::value>
homogeneous_sizeof_helper(index_sequence<Is...>);
template <class T>
struct homogeneous_sizeof_one<T, typename std::enable_if<std::is_class<T>::value>::type>
: decltype(homogeneous_sizeof_helper<T>(
make_index_sequence<determine_tuple_size_<T>::value>())) {
};
template <typename Scalar, typename Base, size_t N> class Adapter : public Base
{
private:
template <std::size_t... Indexes, int X>
Adapter(Vc::index_sequence<Indexes...>, const Scalar,
std::integral_constant<int, X>)
{
static_assert(
X < 3, "Failed to construct an object of type Base. Neither via "
"parenthesis-init, brace-init, nor double-brace init appear to work.");
}
template <std::size_t... Indexes>
Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_,
std::integral_constant<int, 2>)
: Base{{get_dispatcher<Indexes>(x_)...}}
{
}
template <std::size_t... Indexes>
Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_,
std::integral_constant<int, 1>)
: Base{get_dispatcher<Indexes>(x_)...}
{
}
template <std::size_t... Indexes>
Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_,
std::integral_constant<int, 0>)
: Base(get_dispatcher<Indexes>(x_)...)
{
}
template <std::size_t... Indexes>
Adapter(Vc::index_sequence<Indexes...> seq_, const Scalar &x_)
: Adapter(seq_, x_,
preferred_construction<Base, decltype(get_dispatcher<Indexes>(
std::declval<const Scalar &>()))...>())
{
}
public:
static constexpr size_t size() { return N; }
static constexpr size_t Size = N;
using base_type = Base;
using scalar_type = Scalar;
Adapter() = default;
#if defined Vc_CLANG && Vc_CLANG < 0x30700
Vc_INTRINSIC Adapter(const Adapter &x) : Base(x) {}
#else
Adapter(const Adapter &) = default;
#endif
Adapter(Adapter &&) = default;
Adapter &operator=(const Adapter &) = default;
Adapter &operator=(Adapter &&) = default;
template <typename U, size_t TupleSize = determine_tuple_size_<Scalar>::value,
typename Seq = Vc::make_index_sequence<TupleSize>,
typename = enable_if<std::is_convertible<U, Scalar>::value>>
Adapter(U &&x_)
: Adapter(Seq(), static_cast<const Scalar &>(x_))
{
}
template <class F,
class = decltype(static_cast<Scalar>(std::declval<F>()(
size_t())))>
Adapter(F &&fun);
template <typename A0, typename... Args,
typename = typename std::enable_if<
!Traits::is_index_sequence<A0>::value &&
(sizeof...(Args) > 0 || !std::is_convertible<A0, Scalar>::value)>::type>
Adapter(A0 &&arg0_, Args &&... arguments_)
: Base(std::forward<A0>(arg0_), std::forward<Args>(arguments_)...)
{
}
template <typename T,
typename = decltype(Base(std::declval<const std::initializer_list<T> &>()))>
Adapter(const std::initializer_list<T> &l_)
: Base(l_)
{
}
void *operator new(size_t size)
{
return Vc::Common::aligned_malloc<alignof(Adapter)>(size);
}
void *operator new(size_t, void *p_) { return p_; }
void *operator new[](size_t size)
{
return Vc::Common::aligned_malloc<alignof(Adapter)>(size);
}
void *operator new[](size_t , void *p_) { return p_; }
void operator delete(void *ptr_, size_t) { Vc::Common::free(ptr_); }
void operator delete(void *, void *) {}
void operator delete[](void *ptr_, size_t) { Vc::Common::free(ptr_); }
void operator delete[](void *, void *) {}
};
template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
inline void operator==(
const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
inline void operator!=(
const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
inline void operator<=(
const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
inline void operator>=(
const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
inline void operator<(
const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
inline void operator>(
const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
}
}
namespace std
{
template <typename Scalar, typename Base, size_t N>
class tuple_size<Vc::SimdizeDetail::Adapter<Scalar, Base, N>> : public tuple_size<Base>
{
};
template <size_t I, typename Scalar, typename Base, size_t N>
class tuple_element<I, Vc::SimdizeDetail::Adapter<Scalar, Base, N>>
: public tuple_element<I, Base>
{
};
template <typename S, typename T, size_t N>
class allocator<Vc::SimdizeDetail::Adapter<S, T, N>>
: public Vc::Allocator<Vc::SimdizeDetail::Adapter<S, T, N>>
{
public:
template <typename U> struct rebind
{
typedef std::allocator<U> other;
};
};
}
namespace Vc_VERSIONED_NAMESPACE
{
namespace SimdizeDetail
{
template <typename T> static inline T decay_workaround(const T &x) { return x; }
template <typename S, typename T, size_t N, size_t... Indexes>
inline void assign_impl(Adapter<S, T, N> &a, size_t i, const S &x,
Vc::index_sequence<Indexes...>)
{
const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(x)))...> tmp(
decay_workaround(get_dispatcher<Indexes>(x))...);
auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(tmp), 0)...};
if (&unused == &unused) {}
}
template <class S, class... Args>
S construct(std::integral_constant<int, 0>, Args &&... args)
{
return S(std::forward<Args>(args)...);
}
template <class S, class... Args>
S construct(std::integral_constant<int, 1>, Args &&... args)
{
return S{std::forward<Args>(args)...};
}
template <class S, class... Args>
S construct(std::integral_constant<int, 2>, Args &&... args)
{
return S{{std::forward<Args>(args)...}};
}
template <typename S, typename T, size_t N, size_t... Indexes>
inline S extract_impl(const Adapter<S, T, N> &a, size_t i, Vc::index_sequence<Indexes...>)
{
const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[i]))...> tmp(
decay_workaround(get_dispatcher<Indexes>(a)[i])...);
return construct<S>(
preferred_construction<S, decltype(decay_workaround(
get_dispatcher<Indexes>(a)[i]))...>(),
decay_workaround(get_dispatcher<Indexes>(a)[i])...);
}
template <typename S, typename T, std::size_t N, std::size_t... Indexes>
inline Adapter<S, T, N> shifted_impl(const Adapter<S, T, N> &a, int shift,
Vc::index_sequence<Indexes...>)
{
Adapter<S, T, N> r;
auto &&unused = {(get_dispatcher<Indexes>(r) = get_dispatcher<Indexes>(a).shifted(shift), 0)...};
if (&unused == &unused) {}
return r;
}
template <typename S, typename T, size_t N>
inline Adapter<S, T, N> shifted(const Adapter<S, T, N> &a, int shift)
{
return shifted_impl(a, shift, Vc::make_index_sequence<determine_tuple_size<T>()>());
}
template <typename S, typename T, std::size_t N, std::size_t... Indexes>
inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, S &x,
Vc::index_sequence<Indexes...>)
{
const auto &a_const = a;
const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a_const)[0]))...>
tmp{decay_workaround(get_dispatcher<Indexes>(a_const)[i])...};
auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(x), 0)...};
auto &&unused2 = {(get_dispatcher<Indexes>(x) = get_dispatcher<Indexes>(tmp), 0)...};
if (&unused == &unused2) {}
}
template <typename S, typename T, std::size_t N, std::size_t... Indexes>
inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b,
std::size_t j, Vc::index_sequence<Indexes...>)
{
const auto &a_const = a;
const auto &b_const = b;
const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a_const)[0]))...>
tmp{decay_workaround(get_dispatcher<Indexes>(a_const)[i])...};
auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(b_const)[j], 0)...};
auto &&unused2 = {(get_dispatcher<Indexes>(b)[j] = get_dispatcher<Indexes>(tmp), 0)...};
if (&unused == &unused2) {}
}
template <typename S, typename T, std::size_t N>
inline void swap(Adapter<S, T, N> &a, std::size_t i, S &x)
{
swap_impl(a, i, x, Vc::make_index_sequence<determine_tuple_size<T>()>());
}
template <typename S, typename T, std::size_t N>
inline void swap(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b, std::size_t j)
{
swap_impl(a, i, b, j, Vc::make_index_sequence<determine_tuple_size<T>()>());
}
template <typename A> class Scalar
{
using reference = typename std::add_lvalue_reference<A>::type;
using S = typename A::scalar_type;
using IndexSeq = Vc::make_index_sequence<determine_tuple_size<S>()>;
public:
Scalar(reference aa, size_t ii) : a(aa), i(ii) {}
Scalar(const Scalar &) = delete;
Scalar(Scalar &&) = delete;
Scalar &operator=(const Scalar &) = delete;
Scalar &operator=(Scalar &&) = delete;
void operator=(const S &x) { assign_impl(a, i, x, IndexSeq()); }
operator S() const { return extract_impl(a, i, IndexSeq()); }
template <typename AA>
friend inline void swap(Scalar<AA> &&a, typename AA::scalar_type &b);
template <typename AA>
friend inline void swap(typename AA::scalar_type &b, Scalar<AA> &&a);
template <typename AA> friend inline void swap(Scalar<AA> &&a, Scalar<AA> &&b);
private:
reference a;
size_t i;
};
template <typename A> inline void swap(Scalar<A> &&a, typename A::scalar_type &b)
{
swap_impl(a.a, a.i, b, typename Scalar<A>::IndexSeq());
}
template <typename A> inline void swap(typename A::scalar_type &b, Scalar<A> &&a)
{
swap_impl(a.a, a.i, b, typename Scalar<A>::IndexSeq());
}
template <typename A> inline void swap(Scalar<A> &&a, Scalar<A> &&b)
{
swap_impl(a.a, a.i, b.a, b.i, typename Scalar<A>::IndexSeq());
}
template <class S, class T, size_t N, size_t... I>
inline void load_interleaved_impl(Vc::index_sequence<I...>, Adapter<S, T, N> &a,
const S *mem)
{
const InterleavedMemoryWrapper<S, decltype(decay_workaround(get_dispatcher<0>(a)))>
wrapper(const_cast<S *>(mem));
Vc::tie(get_dispatcher<I>(a)...) = wrapper[0];
}
template <class S, class T, size_t N, size_t... I>
inline void store_interleaved_impl(Vc::index_sequence<I...>, const Adapter<S, T, N> &a,
S *mem)
{
InterleavedMemoryWrapper<S, decltype(decay_workaround(get_dispatcher<0>(a)))> wrapper(
mem);
wrapper[0] = Vc::tie(get_dispatcher<I>(a)...);
}
template <typename A> class Interface
{
using reference = typename std::add_lvalue_reference<A>::type;
using IndexSeq =
Vc::make_index_sequence<determine_tuple_size<typename A::scalar_type>()>;
public:
Interface(reference aa) : a(aa) {}
Scalar<A> operator[](size_t i)
{
return {a, i};
}
typename A::scalar_type operator[](size_t i) const
{
return extract_impl(a, i, IndexSeq());
}
A shifted(int amount) const
{
return shifted_impl(a, amount, IndexSeq());
}
void load(const typename A::scalar_type *mem) { load_interleaved(*this, mem); }
void store(typename A::scalar_type *mem) { store_interleaved(*this, mem); }
private:
reference a;
};
}
template <typename S, typename T, size_t N>
inline void assign(SimdizeDetail::Adapter<S, T, N> &a, size_t i, const S &x)
{
SimdizeDetail::assign_impl(
a, i, x, Vc::make_index_sequence<SimdizeDetail::determine_tuple_size<T>()>());
}
template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
Vc_INTRINSIC void assign(V &v, size_t i, typename V::EntryType x)
{
v[i] = x;
}
template <typename S, typename T, size_t N>
inline S extract(const SimdizeDetail::Adapter<S, T, N> &a, size_t i)
{
return SimdizeDetail::extract_impl(
a, i, Vc::make_index_sequence<SimdizeDetail::determine_tuple_size<S>()>());
}
template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
Vc_INTRINSIC typename V::EntryType extract(const V &v, size_t i)
{
return v[i];
}
template <class S, class T, size_t N>
inline void load_interleaved(SimdizeDetail::Adapter<S, T, N> &a, const S *mem)
{
if (SimdizeDetail::homogeneous_sizeof<S>::value == 0) {
Common::unrolled_loop<std::size_t, 0, N>(
[&](std::size_t i) { assign(a, i, mem[i]); });
} else {
constexpr size_t TupleSize = SimdizeDetail::determine_tuple_size_<S>::value;
SimdizeDetail::load_interleaved_impl(Vc::make_index_sequence<TupleSize>(), a,
mem);
}
}
template <
class V, class T,
class = enable_if<Traits::is_simd_vector<V>::value && std::is_arithmetic<T>::value>>
Vc_INTRINSIC void load_interleaved(V &a, const T *mem)
{
a.load(mem, Vc::Unaligned);
}
template <class S, class T, size_t N>
inline void store_interleaved(const SimdizeDetail::Adapter<S, T, N> &a, S *mem)
{
if (SimdizeDetail::homogeneous_sizeof<S>::value == 0) {
Common::unrolled_loop<std::size_t, 0, N>(
[&](std::size_t i) { mem[i] = extract(a, i); });
} else {
constexpr size_t TupleSize = SimdizeDetail::determine_tuple_size_<S>::value;
SimdizeDetail::store_interleaved_impl(Vc::make_index_sequence<TupleSize>(), a,
mem);
}
}
template <
class V, class T,
class = enable_if<Traits::is_simd_vector<V>::value && std::is_arithmetic<T>::value>>
Vc_INTRINSIC void store_interleaved(const V &a, T *mem)
{
a.store(mem, Vc::Unaligned);
}
template <typename S, typename T, size_t N>
SimdizeDetail::Interface<SimdizeDetail::Adapter<S, T, N>> decorate(
SimdizeDetail::Adapter<S, T, N> &a)
{
return {a};
}
template <typename S, typename T, size_t N>
const SimdizeDetail::Interface<const SimdizeDetail::Adapter<S, T, N>> decorate(
const SimdizeDetail::Adapter<S, T, N> &a)
{
return {a};
}
template <class V, class = typename std::enable_if<
Traits::is_simd_vector<typename std::decay<V>::type>::value>>
V &&decorate(V &&v)
{
return std::forward<V>(v);
}
namespace SimdizeDetail
{
template <typename Scalar, typename Base, size_t N>
template <class F, class>
Adapter<Scalar, Base, N>::Adapter(F &&fun)
{
for (size_t i = 0; i < N; ++i) {
Vc::assign(*this, i, fun(i));
}
}
namespace IteratorDetails
{
enum class Mutable { Yes, No };
template <typename It, typename V, size_t I, size_t End>
Vc_INTRINSIC V fromIteratorImpl(enable_if<(I == End), It>)
{
return {};
}
template <typename It, typename V, size_t I, size_t End>
Vc_INTRINSIC V fromIteratorImpl(enable_if<(I < End), It> it)
{
V r = fromIteratorImpl<It, V, I + 1, End>(it);
Traits::decay<decltype(get_dispatcher<I>(r))> tmp;
for (size_t j = 0; j < V::size(); ++j, ++it) {
tmp[j] = get_dispatcher<I>(*it);
}
get_dispatcher<I>(r) = tmp;
return r;
}
template <typename It, typename V>
Vc_INTRINSIC V fromIterator(enable_if<!Traits::is_simd_vector<V>::value, const It &> it)
{
return fromIteratorImpl<It, V, 0, determine_tuple_size<V>()>(it);
}
template <typename It, typename V>
Vc_INTRINSIC V fromIterator(
enable_if<
Traits::is_simd_vector<V>::value && Traits::has_contiguous_storage<It>::value, It>
it)
{
Vc_ASSERT(&*it + 1 == &*(it + 1));
return V(&*it, Vc::Unaligned);
}
template <typename It, typename V>
Vc_INTRINSIC V fromIterator(enable_if<Traits::is_simd_vector<V>::value &&
!Traits::has_contiguous_storage<It>::value,
It>
it)
{
V r;
for (size_t j = 0; j < V::size(); ++j, ++it) {
r[j] = *it;
}
return r;
}
template <typename T, typename value_vector, Mutable> class Pointer;
template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::Yes>
{
static constexpr auto Size = value_vector::size();
public:
value_vector *operator->() { return &data; }
Pointer() = delete;
Pointer(const Pointer &) = delete;
Pointer &operator=(const Pointer &) = delete;
Pointer &operator=(Pointer &&) = delete;
Pointer(Pointer &&) = default;
~Pointer()
{
for (size_t i = 0; i < Size; ++i, ++begin_iterator) {
*begin_iterator = extract(data, i);
}
}
Pointer(const T &it) : data(fromIterator<T, value_vector>(it)), begin_iterator(it) {}
private:
value_vector data;
T begin_iterator;
};
template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::No>
{
static constexpr auto Size = value_vector::size();
public:
const value_vector *operator->() const { return &data; }
Pointer() = delete;
Pointer(const Pointer &) = delete;
Pointer &operator=(const Pointer &) = delete;
Pointer &operator=(Pointer &&) = delete;
Pointer(Pointer &&) = default;
Pointer(const T &it) : data(fromIterator<T, value_vector>(it)) {}
private:
value_vector data;
};
template <typename T, typename value_vector, Mutable M> class Reference;
template <typename T, typename value_vector>
class Reference<T, value_vector, Mutable::Yes> : public value_vector
{
static constexpr auto Size = value_vector::size();
using reference = typename std::add_lvalue_reference<T>::type;
reference scalar_it;
public:
Reference(reference first_it)
: value_vector(fromIterator<T, value_vector>(first_it)), scalar_it(first_it)
{
}
Reference(const Reference &) = delete;
Reference(Reference &&) = default;
Reference &operator=(const Reference &) = delete;
Reference &operator=(Reference &&) = delete;
void operator=(const value_vector &x)
{
static_cast<value_vector &>(*this) = x;
auto it = scalar_it;
for (size_t i = 0; i < Size; ++i, ++it) {
*it = extract(x, i);
}
}
};
#define Vc_OP(op_) \
template <typename T0, typename V0, typename T1, typename V1> \
decltype(std::declval<const V0 &>() op_ std::declval<const V1 &>()) operator op_( \
const Reference<T0, V0, Mutable::Yes> &x, \
const Reference<T1, V1, Mutable::Yes> &y) \
{ \
return static_cast<const V0 &>(x) op_ static_cast<const V1 &>(y); \
}
Vc_ALL_COMPARES(Vc_OP);
Vc_ALL_ARITHMETICS(Vc_OP);
Vc_ALL_BINARY(Vc_OP);
Vc_ALL_LOGICAL(Vc_OP);
Vc_ALL_SHIFTS(Vc_OP);
#undef Vc_OP
template <typename T, typename value_vector>
class Reference<T, value_vector, Mutable::No> : public value_vector
{
static constexpr auto Size = value_vector::size();
public:
Reference(const T &it) : value_vector(fromIterator<T, value_vector>(it)) {}
Reference(const Reference &) = delete;
Reference(Reference &&) = default;
Reference &operator=(const Reference &) = delete;
Reference &operator=(Reference &&) = delete;
void operator=(const value_vector &x) = delete;
};
template <typename T, size_t N,
IteratorDetails::Mutable M =
(Traits::is_output_iterator<T>::value ? Mutable::Yes : Mutable::No),
typename V = simdize<typename std::iterator_traits<T>::value_type, N>,
size_t Size = V::Size,
typename = typename std::iterator_traits<T>::iterator_category>
class Iterator;
template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size_>
class Iterator<T, N, M, V, Size_, std::forward_iterator_tag>
: public std::iterator<typename std::iterator_traits<T>::iterator_category, V,
typename std::iterator_traits<T>::difference_type,
IteratorDetails::Pointer<T, V, M>,
IteratorDetails::Reference<T, V, M>>
{
public:
using pointer = IteratorDetails::Pointer<T, V, M>;
using reference = IteratorDetails::Reference<T, V, M>;
using const_pointer = IteratorDetails::Pointer<T, V, IteratorDetails::Mutable::No>;
using const_reference =
IteratorDetails::Reference<T, V, IteratorDetails::Mutable::No>;
static constexpr std::size_t size() { return Size_; }
static constexpr std::size_t Size = Size_;
Iterator() = default;
Iterator(const T &x) : scalar_it(x) {}
Iterator(T &&x) : scalar_it(std::move(x)) {}
Iterator &operator=(const T &x)
{
scalar_it = x;
return *this;
}
Iterator &operator=(T &&x)
{
scalar_it = std::move(x);
return *this;
}
Iterator(const Iterator &) = default;
Iterator(Iterator &&) = default;
Iterator &operator=(const Iterator &) = default;
Iterator &operator=(Iterator &&) = default;
Iterator &operator++()
{
std::advance(scalar_it, Size);
return *this;
}
Iterator operator++(int)
{
Iterator copy(*this);
operator++();
return copy;
}
bool operator==(const Iterator &rhs) const
{
#ifndef NDEBUG
if (scalar_it == rhs.scalar_it) {
return true;
} else {
T it(scalar_it);
for (size_t i = 1; i < Size; ++i) {
Vc_ASSERT((++it != rhs.scalar_it));
}
return false;
}
#else
return scalar_it == rhs.scalar_it;
#endif
}
bool operator!=(const Iterator &rhs) const
{
return !operator==(rhs);
}
pointer operator->() { return scalar_it; }
reference operator*() { return scalar_it; }
const_pointer operator->() const { return scalar_it; }
const_reference operator*() const { return scalar_it; }
operator const T &() const { return scalar_it; }
protected:
T scalar_it;
};
template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
class Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
: public Iterator<T, N, M, V, Size, std::forward_iterator_tag>
{
using Base = Iterator<T, N, M, V, Size, std::forward_iterator_tag>;
protected:
using Base::scalar_it;
public:
using pointer = typename Base::pointer;
using reference = typename Base::reference;
using const_pointer = typename Base::const_pointer;
using const_reference = typename Base::const_reference;
using Iterator<T, N, M, V, Size,
std::forward_iterator_tag>::Iterator;
Iterator &operator--()
{
std::advance(scalar_it, -Size);
return *this;
}
Iterator operator--(int)
{
Iterator copy(*this);
operator--();
return copy;
}
};
template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
class Iterator<T, N, M, V, Size, std::random_access_iterator_tag>
: public Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
{
using Base = Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>;
protected:
using Base::scalar_it;
public:
using pointer = typename Base::pointer;
using reference = typename Base::reference;
using const_pointer = typename Base::const_pointer;
using const_reference = typename Base::const_reference;
using difference_type = typename std::iterator_traits<T>::difference_type;
using Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>::
Iterator;
Iterator &operator+=(difference_type n)
{
scalar_it += n * difference_type(Size);
return *this;
}
Iterator operator+(difference_type n) const { return Iterator(*this) += n; }
Iterator &operator-=(difference_type n)
{
scalar_it -= n * difference_type(Size);
return *this;
}
Iterator operator-(difference_type n) const { return Iterator(*this) -= n; }
difference_type operator-(const Iterator &rhs) const
{
constexpr difference_type n = Size;
Vc_ASSERT((scalar_it - rhs.scalar_it) % n ==
0);
return (scalar_it - rhs.scalar_it) / n;
}
bool operator<(const Iterator &rhs) const
{
return rhs.scalar_it - scalar_it >= difference_type(Size);
}
bool operator>(const Iterator &rhs) const
{
return scalar_it - rhs.scalar_it >= difference_type(Size);
}
bool operator<=(const Iterator &rhs) const
{
return rhs.scalar_it - scalar_it >= difference_type(Size) - 1;
}
bool operator>=(const Iterator &rhs) const
{
return scalar_it - rhs.scalar_it >= difference_type(Size) - 1;
}
reference operator[](difference_type i) { return *(*this + i); }
const_reference operator[](difference_type i) const { return *(*this + i); }
};
template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
Iterator<T, N, M, V, Size, std::random_access_iterator_tag> operator+(
typename Iterator<T, N, M, V, Size, std::random_access_iterator_tag>::difference_type
n,
const Iterator<T, N, M, V, Size, std::random_access_iterator_tag> &i)
{
return i + n;
}
}
template <typename T, size_t N, typename MT>
struct ReplaceTypes<T, N, MT, Category::ForwardIterator>
{
using type = IteratorDetails::Iterator<T, N>;
};
template <typename T, size_t N, typename MT>
struct ReplaceTypes<T, N, MT, Category::BidirectionalIterator>
{
using type = IteratorDetails::Iterator<T, N>;
};
template <typename T, size_t N, typename MT>
struct ReplaceTypes<T, N, MT, Category::RandomAccessIterator>
{
using type = IteratorDetails::Iterator<T, N>;
};
template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
std::size_t Offset>
Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size_<S>::value && M::Size == N), void>
conditional_assign(Adapter<S, T, N> &, const M &, const U &)
{
}
template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
std::size_t Offset = 0>
Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size_<S>::value && M::Size == N), void>
conditional_assign(Adapter<S, T, N> &lhs, const M &mask, const U &rhs)
{
using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
using M2 = typename V::mask_type;
conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask), get_dispatcher<Offset>(rhs));
conditional_assign<Op, S, T, N, M, U, Offset + 1>(lhs, mask, rhs);
}
template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
std::size_t Offset>
Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size_<S>::value && M::Size == N), void>
conditional_assign(Adapter<S, T, N> &, const M &)
{
}
template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
std::size_t Offset = 0>
Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size_<S>::value && M::Size == N), void>
conditional_assign(Adapter<S, T, N> &lhs, const M &mask)
{
using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
using M2 = typename V::mask_type;
conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask));
conditional_assign<Op, S, T, N, M, Offset + 1>(lhs, mask);
}
}
template <typename T, size_t N = 0, typename MT = void>
using simdize = SimdizeDetail::simdize<T, N, MT>;
#define Vc_SIMDIZE_INTERFACE(MEMBERS_) \
template <std::size_t N_> \
inline auto vc_get_()->decltype(std::get<N_>(std::tie MEMBERS_)) \
{ \
return std::get<N_>(std::tie MEMBERS_); \
} \
template <std::size_t N_> \
inline auto vc_get_() const->decltype(std::get<N_>(std::tie MEMBERS_)) \
{ \
return std::get<N_>(std::tie MEMBERS_); \
} \
enum : std::size_t { \
tuple_size = std::tuple_size<decltype(std::make_tuple MEMBERS_)>::value \
}
}
namespace std
{
using Vc::SimdizeDetail::swap;
}
#endif
namespace Vc_VERSIONED_NAMESPACE
{
#ifdef DOXYGEN
template <class InputIt, class UnaryFunction>
UnaryFunction simd_for_each(InputIt first, InputIt last, UnaryFunction f);
#else
template <class InputIt, class UnaryFunction,
class ValueType = typename std::iterator_traits<InputIt>::value_type>
inline enable_if<
Traits::is_functor_argument_immutable<UnaryFunction, simdize<ValueType>>::value,
UnaryFunction>
simd_for_each(InputIt first, InputIt last, UnaryFunction f)
{
typedef simdize<ValueType> V;
typedef simdize<ValueType, 1> V1;
const auto lastV = last - V::Size + 1;
for (; first < lastV; first += V::Size) {
V tmp;
load_interleaved(tmp, std::addressof(*first));
f(tmp);
}
for (; first != last; ++first) {
V1 tmp;
load_interleaved(tmp, std::addressof(*first));
f(tmp);
}
return f;
}
template <typename InputIt, typename UnaryFunction,
class ValueType = typename std::iterator_traits<InputIt>::value_type>
inline enable_if<
!Traits::is_functor_argument_immutable<UnaryFunction, simdize<ValueType>>::value,
UnaryFunction>
simd_for_each(InputIt first, InputIt last, UnaryFunction f)
{
typedef simdize<ValueType> V;
typedef simdize<ValueType, 1> V1;
const auto lastV = last - V::size() + 1;
for (; first < lastV; first += V::size()) {
V tmp;
load_interleaved(tmp, std::addressof(*first));
f(tmp);
store_interleaved(tmp, std::addressof(*first));
}
for (; first != last; ++first) {
V1 tmp;
load_interleaved(tmp, std::addressof(*first));
f(tmp);
store_interleaved(tmp, std::addressof(*first));
}
return f;
}
#endif
template <typename InputIt, typename UnaryFunction,
class ValueType = typename std::iterator_traits<InputIt>::value_type>
inline enable_if<
Traits::is_functor_argument_immutable<UnaryFunction, simdize<ValueType>>::value,
UnaryFunction>
simd_for_each_n(InputIt first, std::size_t count, UnaryFunction f)
{
typename std::make_signed<size_t>::type len = count;
typedef simdize<ValueType> V;
typedef simdize<ValueType, 1> V1;
for (; len >= int(V::size()); len -= V::Size, first += V::Size) {
V tmp;
load_interleaved(tmp, std::addressof(*first));
f(tmp);
}
for (; len != 0; --len, ++first) {
V1 tmp;
load_interleaved(tmp, std::addressof(*first));
f(tmp);
}
return f;
}
template <typename InputIt, typename UnaryFunction,
class ValueType = typename std::iterator_traits<InputIt>::value_type>
inline enable_if<
!Traits::is_functor_argument_immutable<UnaryFunction, simdize<ValueType>>::value,
UnaryFunction>
simd_for_each_n(InputIt first, std::size_t count, UnaryFunction f)
{
typename std::make_signed<size_t>::type len = count;
typedef simdize<ValueType> V;
typedef simdize<ValueType, 1> V1;
for (; len >= int(V::size()); len -= V::Size, first += V::Size) {
V tmp;
load_interleaved(tmp, std::addressof(*first));
f(tmp);
store_interleaved(tmp, std::addressof(*first));
}
for (; len != 0; --len, ++first) {
V1 tmp;
load_interleaved(tmp, std::addressof(*first));
f(tmp);
store_interleaved(tmp, std::addressof(*first));
}
return f;
}
}
#endif