#ifndef VC_COMMON_ALGORITHMS_H_ #define VC_COMMON_ALGORITHMS_H_ #ifndef VC_COMMON_SIMDIZE_H_ #define VC_COMMON_SIMDIZE_H_ #include #include #ifndef VC_ALLOCATOR_H_ #define VC_ALLOCATOR_H_ #include #include #include #include #ifdef Vc_MSVC #define Vc_DECLARE_ALLOCATOR(Type) \ namespace std \ { \ template <> class allocator : public ::Vc::Allocator \ { \ public: \ template struct rebind { \ typedef ::std::allocator other; \ }; \ \ const allocator &select_on_container_copy_construction() const { return *this; } \ }; \ } #else #define Vc_DECLARE_ALLOCATOR(Type) \ namespace std \ { \ template <> class allocator : public ::Vc::Allocator \ { \ public: \ template struct rebind { \ typedef ::std::allocator other; \ }; \ }; \ } #endif namespace Vc_VERSIONED_NAMESPACE { using std::size_t; using std::ptrdiff_t; template 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 struct rebind { typedef Allocator other; }; Allocator() throw() { } Allocator(const Allocator&) throw() { } template Allocator(const Allocator&) 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(::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(p)[-1] = pp; } return reinterpret_cast(p); } void deallocate(pointer p, size_type) { if (ExtraBytes > 0) { p = reinterpret_cast(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 void construct(U* p, Args&&... args) { ::new(p) U(std::forward(args)...); } template void destroy(U* p) { p->~U(); } #endif }; template inline bool operator==(const Allocator&, const Allocator&) { return true; } template inline bool operator!=(const Allocator&, const Allocator&) { return false; } } namespace std { template class allocator > : public ::Vc::Allocator > { public: template struct rebind { typedef ::std::allocator other; }; #ifdef Vc_MSVC const allocator &select_on_container_copy_construction() const { return *this; } #endif }; template class allocator> : public ::Vc::Allocator> { public: template struct rebind { typedef ::std::allocator other; }; #ifdef Vc_MSVC const allocator &select_on_container_copy_construction() const { return *this; } #endif }; template class allocator> : public ::Vc::Allocator> { public: template struct rebind { typedef ::std::allocator other; }; #ifdef Vc_MSVC const allocator &select_on_container_copy_construction() const { return *this; } #endif }; template class allocator> : public ::Vc::Allocator> { public: template struct rebind { typedef ::std::allocator 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 struct InterleavedMemoryAccessBase { typedef typename std::conditional< Readonly, typename std::add_const::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 Vc_INTRINSIC void deinterleave(Vs &&... vs) const { Impl::deinterleave(m_data, m_indexes, std::forward(vs)...); } protected: using Impl = Vc::Detail::InterleaveImpl; template Vc_INTRINSIC void callInterleave(T &&a, index_sequence) { Impl::interleave(m_data, m_indexes, a[Indexes]...); } }; template struct InterleavedMemoryReadAccess : public InterleavedMemoryAccessBase { typedef InterleavedMemoryAccessBase 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 Vc_ALWAYS_INLINE T deinterleave_unpack(index_sequence) const { T r; Base::Impl::deinterleave(this->m_data, this->m_indexes, std::get(r)...); return r; } template ::value && std::is_same( std::declval()))>>::value)>> Vc_ALWAYS_INLINE operator T() const { return deinterleave_unpack(make_index_sequence::value>()); } }; template 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 struct CheckIndexesUnique > { static Vc_INTRINSIC void test(const SuccessiveEntries &) {} }; template struct InterleavedMemoryAccess : public InterleavedMemoryReadAccess { typedef InterleavedMemoryAccessBase Base; typedef typename Base::Ta Ta; Vc_ALWAYS_INLINE InterleavedMemoryAccess(Ta *data, typename I::AsArg indexes) : InterleavedMemoryReadAccess(data, indexes) { CheckIndexesUnique::test(indexes); } template Vc_ALWAYS_INLINE void operator=(VectorReferenceArray &&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()); } template Vc_ALWAYS_INLINE void operator=(VectorReferenceArray &&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()); } }; template class InterleavedMemoryWrapper { typedef typename std::conditional::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; using Access = typename std::conditional::value, ReadAccess, InterleavedMemoryAccess>::type; using ReadSuccessiveEntries = InterleavedMemoryReadAccess>; using AccessSuccessiveEntries = typename std::conditional< std::is_const::value, ReadSuccessiveEntries, InterleavedMemoryAccess>>::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(s)) { } template Vc_ALWAYS_INLINE enable_if::value && std::is_convertible::value && !std::is_const::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 inline Common::InterleavedMemoryWrapper make_interleave_wrapper(S *s) { return Common::InterleavedMemoryWrapper(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 struct Typelist; enum class Category { None, ArithmeticVectorizable, InputIterator, OutputIterator, ForwardIterator, BidirectionalIterator, RandomAccessIterator, ClassTemplate }; template constexpr Category iteratorCategories(int, ItCat * = nullptr) { return is_base_of::value ? Category::RandomAccessIterator : is_base_of::value ? Category::BidirectionalIterator : is_base_of::value ? Category::ForwardIterator : is_base_of::value ? Category::OutputIterator : is_base_of::value ? Category::InputIterator : Category::None; } template constexpr enable_if::value, Category> iteratorCategories(float) { return Category::RandomAccessIterator; } template constexpr Category iteratorCategories(...) { return Category::None; } template struct is_class_template : public false_type { }; template