29 #ifndef VC_COMMON_SIMDARRAY_H_
30 #define VC_COMMON_SIMDARRAY_H_
34 #if defined Vc_DEBUG_SIMD_CAST || defined Vc_DEBUG_SORTED
40 #include "writemaskedvector.h"
41 #include "simdarrayhelper.h"
42 #include "simdmaskarray.h"
44 #include "interleave.h"
45 #include "indexsequence.h"
46 #include "transpose.h"
49 namespace Vc_VERSIONED_NAMESPACE
54 template <
typename T> T Vc_INTRINSIC Vc_PURE product_helper_(
const T &l,
const T &r) {
return l * r; }
55 template <
typename T> T Vc_INTRINSIC Vc_PURE sum_helper_(
const T &l,
const T &r) {
return l + r; }
59 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
60 inline SimdArray<T, N, V, M>
min(
const SimdArray<T, N, V, M> &x,
61 const SimdArray<T, N, V, M> &y);
62 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
63 inline SimdArray<T, N, V, M>
max(
const SimdArray<T, N, V, M> &x,
64 const SimdArray<T, N, V, M> &y);
71 #define Vc_CURRENT_CLASS_NAME SimdArray
81 template <
typename T, std::
size_t N,
typename VectorType_>
84 ((Common::nextPowerOfTwo(N) * (sizeof(VectorType_) / VectorType_::size()) - 1) & 127) +
86 1) SimdArray<T, N, VectorType_, N>
88 static_assert(std::is_same<T, double>::value || std::is_same<T, float>::value ||
89 std::is_same<T, int32_t>::value ||
90 std::is_same<T, uint32_t>::value ||
91 std::is_same<T, int16_t>::value ||
92 std::is_same<T, uint16_t>::value,
93 "SimdArray<T, N> may only be used with T = { double, float, int32_t, uint32_t, "
94 "int16_t, uint16_t }");
97 using VectorType = VectorType_;
98 using vector_type = VectorType;
99 using storage_type = vector_type;
100 using vectorentry_type =
typename vector_type::VectorEntryType;
101 using value_type = T;
102 using mask_type = SimdMaskArray<T, N, vector_type>;
103 using index_type = SimdArray<int, N>;
104 static constexpr std::size_t size() {
return N; }
105 using Mask = mask_type;
106 using MaskType = Mask;
107 using MaskArgument =
const MaskType &;
108 using VectorEntryType = vectorentry_type;
109 using EntryType = value_type;
110 using IndexType = index_type;
111 using AsArg =
const SimdArray &;
112 static constexpr std::size_t Size = size();
116 Vc_INTRINSIC SimdArray() =
default;
119 Vc_INTRINSIC SimdArray(
const SimdArray &) =
default;
120 Vc_INTRINSIC SimdArray(SimdArray &&) =
default;
121 Vc_INTRINSIC SimdArray &operator=(
const SimdArray &) =
default;
124 Vc_INTRINSIC SimdArray(
const value_type &a) : data(a) {}
125 Vc_INTRINSIC SimdArray(value_type &a) : data(a) {}
126 Vc_INTRINSIC SimdArray(value_type &&a) : data(a) {}
129 typename = enable_if<std::is_same<U, int>::value && !std::is_same<int, value_type>::value>>
130 Vc_INTRINSIC SimdArray(U a)
131 : SimdArray(static_cast<value_type>(a))
136 template <
typename U,
typename V>
137 Vc_INTRINSIC SimdArray(
const SimdArray<U, N, V> &x, enable_if<N == V::size()> = nullarg)
138 : data(
simd_cast<vector_type>(internal_data(x)))
141 template <
typename U,
typename V>
142 Vc_INTRINSIC SimdArray(
const SimdArray<U, N, V> &x,
143 enable_if<(N > V::size() && N <= 2 * V::size())> = nullarg)
144 : data(
simd_cast<vector_type>(internal_data(internal_data0(x)), internal_data(internal_data1(x))))
147 template <
typename U,
typename V>
148 Vc_INTRINSIC SimdArray(
const SimdArray<U, N, V> &x,
149 enable_if<(N > 2 * V::size() && N <= 4 * V::size())> = nullarg)
150 : data(
simd_cast<vector_type>(internal_data(internal_data0(internal_data0(x))),
151 internal_data(internal_data1(internal_data0(x))),
152 internal_data(internal_data0(internal_data1(x))),
153 internal_data(internal_data1(internal_data1(x)))))
157 template <
typename V, std::
size_t Pieces, std::
size_t Index>
158 Vc_INTRINSIC SimdArray(Common::Segment<V, Pieces, Index> &&x)
159 : data(
simd_cast<vector_type, Index>(x.data))
163 Vc_INTRINSIC SimdArray(
const std::initializer_list<value_type> &init)
166 #if defined Vc_CXX14 && 0 // doesn't compile yet
167 static_assert(init.size() == size(),
"The initializer_list argument to "
168 "SimdArray<T, N> must contain exactly N "
171 Vc_ASSERT(init.size() == size());
178 typename = enable_if<Traits::is_simd_vector<V>::value && !Traits::isSimdArray<V>::value>>
179 explicit Vc_INTRINSIC SimdArray(
const V &x)
186 template <
typename V,
187 typename = enable_if<
189 std::is_convertible<T, typename V::EntryType>::value && V::size() == N>>
190 Vc_INTRINSIC
operator V()
const
195 #include "gatherinterface.h"
198 template <
typename... Args,
199 typename = enable_if<!Traits::is_cast_arguments<Args...>::value &&
200 !Traits::is_gather_signature<Args...>::value &&
201 !Traits::is_initializer_list<Args...>::value>>
202 explicit Vc_INTRINSIC SimdArray(Args &&... args)
203 : data(
std::forward<Args>(args)...)
207 template <std::
size_t Offset>
208 explicit Vc_INTRINSIC SimdArray(
209 Common::AddOffset<VectorSpecialInitializerIndexesFromZero, Offset>)
212 data += value_type(Offset);
215 Vc_INTRINSIC
void setZero() { data.setZero(); }
216 Vc_INTRINSIC
void setZero(mask_type k) { data.setZero(internal_data(k)); }
217 Vc_INTRINSIC
void setZeroInverted() { data.setZeroInverted(); }
218 Vc_INTRINSIC
void setZeroInverted(mask_type k) { data.setZeroInverted(internal_data(k)); }
220 Vc_INTRINSIC
void setQnan() { data.setQnan(); }
221 Vc_INTRINSIC
void setQnan(mask_type m) { data.setQnan(internal_data(m)); }
224 template <
typename Op,
typename... Args>
225 static Vc_INTRINSIC SimdArray fromOperation(Op op, Args &&... args)
228 Common::unpackArgumentsAuto(op, r.data, std::forward<Args>(args)...);
232 template <
typename Op,
typename... Args>
233 static Vc_INTRINSIC
void callOperation(Op op, Args &&... args)
235 Common::unpackArgumentsAuto(op,
nullptr, std::forward<Args>(args)...);
238 static Vc_INTRINSIC SimdArray
Zero()
242 static Vc_INTRINSIC SimdArray
One()
250 static Vc_INTRINSIC SimdArray Random()
252 return fromOperation(Common::Operations::random());
255 template <
typename... Args> Vc_INTRINSIC
void load(Args &&... args)
257 data.load(std::forward<Args>(args)...);
260 template <
typename... Args> Vc_INTRINSIC
void store(Args &&... args)
const
262 data.store(std::forward<Args>(args)...);
265 Vc_INTRINSIC mask_type operator!()
const
276 Vc_INTRINSIC SimdArray
operator+()
const {
return *
this; }
278 Vc_INTRINSIC SimdArray operator~()
const
283 template <
typename U,
284 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
289 template <
typename U,
290 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
291 Vc_INTRINSIC SimdArray &operator<<=(U x)
296 template <
typename U,
297 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
298 Vc_INTRINSIC Vc_CONST SimdArray operator>>(U x)
const
302 template <
typename U,
303 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
304 Vc_INTRINSIC SimdArray &operator>>=(U x)
310 #define Vc_BINARY_OPERATOR_(op) \
311 Vc_INTRINSIC Vc_CONST SimdArray operator op(const SimdArray &rhs) const \
313 return {data op rhs.data}; \
315 Vc_INTRINSIC SimdArray &operator op##=(const SimdArray &rhs) \
317 data op## = rhs.data; \
320 Vc_ALL_ARITHMETICS(Vc_BINARY_OPERATOR_);
321 Vc_ALL_BINARY(Vc_BINARY_OPERATOR_);
322 Vc_ALL_SHIFTS(Vc_BINARY_OPERATOR_);
323 #undef Vc_BINARY_OPERATOR_
325 #define Vc_COMPARES(op) \
326 Vc_INTRINSIC mask_type operator op(const SimdArray &rhs) const \
328 return {data op rhs.data}; \
330 Vc_ALL_COMPARES(Vc_COMPARES);
334 Vc_INTRINSIC Vc_DEPRECATED(
"use isnegative(x) instead")
MaskType isNegative()
const
339 Vc_INTRINSIC decltype(std::declval<vector_type &>()[0]) operator[](
std::
size_t i)
343 Vc_INTRINSIC value_type operator[](std::size_t i)
const {
return data[i]; }
345 Vc_INTRINSIC Common::WriteMaskedVector<SimdArray, mask_type> operator()(
const mask_type &k)
350 Vc_INTRINSIC
void assign(
const SimdArray &v,
const mask_type &k)
352 data.assign(v.data, internal_data(k));
356 #define Vc_REDUCTION_FUNCTION_(name_) \
357 Vc_INTRINSIC Vc_PURE value_type name_() const { return data.name_(); } \
358 Vc_INTRINSIC Vc_PURE value_type name_(mask_type mask) const \
360 return data.name_(internal_data(mask)); \
362 Vc_NOTHING_EXPECTING_SEMICOLON
363 Vc_REDUCTION_FUNCTION_(
min);
364 Vc_REDUCTION_FUNCTION_(
max);
365 Vc_REDUCTION_FUNCTION_(product);
366 Vc_REDUCTION_FUNCTION_(sum);
367 #undef Vc_REDUCTION_FUNCTION_
368 Vc_INTRINSIC Vc_PURE SimdArray partialSum()
const {
return data.partialSum(); }
370 template <
typename F> Vc_INTRINSIC SimdArray apply(F &&f)
const
372 return {data.apply(std::forward<F>(f))};
374 template <
typename F> Vc_INTRINSIC SimdArray apply(F &&f,
const mask_type &k)
const
376 return {data.apply(std::forward<F>(f), k)};
379 Vc_INTRINSIC SimdArray
shifted(
int amount)
const
381 return {data.shifted(amount)};
384 template <std::
size_t NN>
385 Vc_INTRINSIC SimdArray
shifted(
int amount,
const SimdArray<value_type, NN> &shiftIn)
388 return {data.shifted(amount, simd_cast<VectorType>(shiftIn))};
391 Vc_INTRINSIC SimdArray rotated(
int amount)
const
393 return {data.rotated(amount)};
397 Vc_INTRINSIC Vc_DEPRECATED(
"use exponent(x) instead") SimdArray
exponent()
const
402 Vc_INTRINSIC SimdArray interleaveLow(SimdArray x)
const
404 return {data.interleaveLow(x.data)};
406 Vc_INTRINSIC SimdArray interleaveHigh(SimdArray x)
const
408 return {data.interleaveHigh(x.data)};
411 Vc_INTRINSIC SimdArray reversed()
const
413 return {data.reversed()};
416 Vc_INTRINSIC SimdArray sorted()
const
418 return {data.sorted()};
421 template <
typename G>
static Vc_INTRINSIC SimdArray generate(
const G &gen)
423 return {VectorType::generate(gen)};
426 Vc_INTRINSIC Vc_DEPRECATED(
"use copysign(x, y) instead") SimdArray
427 copySign(const SimdArray &reference)
const
432 friend VectorType &internal_data<>(SimdArray &x);
433 friend const VectorType &internal_data<>(
const SimdArray &x);
436 Vc_INTRINSIC SimdArray(VectorType &&x) : data(
std::move(x)) {}
438 Vc_FREE_STORE_OPERATORS_ALIGNED(
alignof(storage_type));
443 template <
typename T, std::
size_t N,
typename VectorType> constexpr std::size_t SimdArray<T, N, VectorType, N>::Size;
444 template <
typename T, std::
size_t N,
typename VectorType>
446 template <
typename T, std::
size_t N,
typename VectorType>
447 Vc_INTRINSIC VectorType &internal_data(SimdArray<T, N, VectorType, N> &x)
451 template <
typename T, std::
size_t N,
typename VectorType>
452 Vc_INTRINSIC
const VectorType &internal_data(
const SimdArray<T, N, VectorType, N> &x)
458 template <
typename T, std::
size_t N,
typename VectorType>
459 template <
typename MT,
typename IT>
463 data.
gather(mem, std::forward<IT>(indexes));
465 template <
typename T, std::
size_t N,
typename VectorType>
466 template <
typename MT,
typename IT>
471 data.
gather(mem, std::forward<IT>(indexes), mask);
507 template <
typename T,
size_t N,
typename V,
size_t Wt>
508 class alignas(((Common::nextPowerOfTwo(N) * (sizeof(V) / V::size()) - 1) & 127) +
512 static_assert(std::is_same<T, double>::value ||
513 std::is_same<T, float>::value ||
514 std::is_same<T, int32_t>::value ||
515 std::is_same<T, uint32_t>::value ||
516 std::is_same<T, int16_t>::value ||
517 std::is_same<T, uint16_t>::value,
"SimdArray<T, N> may only be used with T = { double, float, int32_t, uint32_t, int16_t, uint16_t }");
520 std::is_same<typename V::EntryType, typename V::VectorEntryType>::value ||
522 (N % V::size() == 0),
523 "SimdArray<(un)signed short, N> on MIC only works correctly for N = k * "
524 "MIC::(u)short_v::size(), i.e. k * 16.");
526 using my_traits = SimdArrayTraits<T, N>;
527 static constexpr std::size_t N0 = my_traits::N0;
528 static constexpr std::size_t N1 = my_traits::N1;
529 using Split = Common::Split<N0>;
530 template <
typename U, std::
size_t K>
using CArray = U[K];
533 using storage_type0 =
typename my_traits::storage_type0;
534 using storage_type1 =
typename my_traits::storage_type1;
535 static_assert(storage_type0::size() == N0,
"");
540 using vector_type = V;
541 using vectorentry_type =
typename storage_type0::vectorentry_type;
542 typedef vectorentry_type alias_type Vc_MAY_ALIAS;
563 static constexpr std::size_t size() {
return N; }
566 using Mask = mask_type;
568 using MaskType =
Mask;
570 using VectorEntryType = vectorentry_type;
578 static constexpr std::size_t MemoryAlignment =
587 static Vc_INTRINSIC SimdArray
Zero()
593 static Vc_INTRINSIC SimdArray
One()
605 static Vc_INTRINSIC SimdArray Random()
607 return fromOperation(Common::Operations::random());
611 template <
typename G>
static Vc_INTRINSIC SimdArray generate(
const G &gen)
613 auto tmp = storage_type0::generate(gen);
618 return {std::move(tmp),
619 storage_type1::generate([&](std::size_t i) {
return gen(i + N0); })};
627 SimdArray() =
default;
634 Vc_INTRINSIC SimdArray(value_type a) : data0(a), data1(a) {}
637 typename = enable_if<std::is_same<U, int>::value && !std::is_same<int, value_type>::value>>
639 : SimdArray(static_cast<value_type>(a))
645 SimdArray(
const SimdArray &) =
default;
646 SimdArray(SimdArray &&) =
default;
647 SimdArray &operator=(
const SimdArray &) =
default;
650 template <
typename U,
652 typename = enable_if<Traits::is_load_store_flag<Flags>::value>>
653 explicit Vc_INTRINSIC SimdArray(
const U *mem, Flags f = Flags())
654 : data0(mem, f), data1(mem + storage_type0::size(), f)
663 template <
typename U, std::size_t Extent,
typename Flags =
DefaultLoadTag,
664 typename = enable_if<Traits::is_load_store_flag<Flags>::value>>
665 explicit Vc_INTRINSIC SimdArray(CArray<U, Extent> &mem, Flags f = Flags())
666 : data0(&mem[0], f), data1(&mem[storage_type0::size()], f)
672 template <
typename U, std::size_t Extent,
typename Flags =
DefaultLoadTag,
673 typename = enable_if<Traits::is_load_store_flag<Flags>::value>>
674 explicit Vc_INTRINSIC SimdArray(
const CArray<U, Extent> &mem, Flags f = Flags())
675 : data0(&mem[0], f), data1(&mem[storage_type0::size()], f)
680 Vc_INTRINSIC SimdArray(
const std::initializer_list<value_type> &init)
682 , data1(init.begin() + storage_type0::size(),
Vc::
Unaligned)
684 #if defined Vc_CXX14 && 0 // doesn't compile yet
685 static_assert(init.size() == size(),
"The initializer_list argument to "
686 "SimdArray<T, N> must contain exactly N "
689 Vc_ASSERT(init.size() == size());
693 #include "gatherinterface.h"
696 template <
typename... Args,
697 typename = enable_if<!Traits::is_cast_arguments<Args...>::value &&
698 !Traits::is_initializer_list<Args...>::value &&
699 !Traits::is_gather_signature<Args...>::value &&
700 !Traits::is_load_arguments<Args...>::value>>
701 explicit Vc_INTRINSIC SimdArray(Args &&... args)
702 : data0(Split::lo(args)...)
704 , data1(Split::hi(
std::forward<Args>(args))...)
709 template <
typename W>
710 Vc_INTRINSIC
explicit SimdArray(
712 enable_if<(Traits::is_simd_vector<W>::value && Traits::simd_vector_size<W>::value == N &&
713 !(std::is_convertible<Traits::entry_type_of<W>, T>::value &&
714 Traits::isSimdArray<W>::value))> = nullarg)
715 : data0(Split::lo(x)), data1(Split::hi(x))
720 template <
typename W>
721 Vc_INTRINSIC SimdArray(
723 enable_if<(Traits::isSimdArray<W>::value && Traits::simd_vector_size<W>::value == N &&
724 std::is_convertible<Traits::entry_type_of<W>, T>::value)> = nullarg)
725 : data0(Split::lo(x)), data1(Split::hi(x))
731 template <
typename W,
732 typename = enable_if<
733 Traits::is_simd_vector<W>::value && !Traits::isSimdArray<W>::value &&
734 std::is_convertible<T, typename W::EntryType>::value && W::size() == N>>
742 Vc_INTRINSIC
void setZero()
747 Vc_INTRINSIC
void setZero(
const mask_type &k)
749 data0.setZero(Split::lo(k));
750 data1.setZero(Split::hi(k));
752 Vc_INTRINSIC
void setZeroInverted()
754 data0.setZeroInverted();
755 data1.setZeroInverted();
757 Vc_INTRINSIC
void setZeroInverted(
const mask_type &k)
759 data0.setZeroInverted(Split::lo(k));
760 data1.setZeroInverted(Split::hi(k));
764 Vc_INTRINSIC
void setQnan() {
768 Vc_INTRINSIC
void setQnan(
const mask_type &m) {
769 data0.setQnan(Split::lo(m));
770 data1.setQnan(Split::hi(m));
774 template <
typename Op,
typename... Args>
775 static Vc_INTRINSIC SimdArray fromOperation(Op op, Args &&... args)
778 storage_type0::fromOperation(op, Split::lo(args)...),
781 storage_type1::fromOperation(op, Split::hi(std::forward<Args>(args))...)};
786 template <
typename Op,
typename... Args>
787 static Vc_INTRINSIC
void callOperation(Op op, Args &&... args)
789 storage_type0::callOperation(op, Split::lo(args)...);
790 storage_type1::callOperation(op, Split::hi(std::forward<Args>(args))...);
794 template <
typename U,
typename... Args> Vc_INTRINSIC
void load(
const U *mem, Args &&... args)
796 data0.load(mem, Split::lo(args)...);
798 data1.load(mem + storage_type0::size(), Split::hi(std::forward<Args>(args))...);
801 template <
typename U,
typename... Args> Vc_INTRINSIC
void store(U *mem, Args &&... args)
const
803 data0.store(mem, Split::lo(args)...);
805 data1.store(mem + storage_type0::size(), Split::hi(std::forward<Args>(args))...);
808 Vc_INTRINSIC mask_type operator!()
const
810 return {!data0, !data1};
815 return {-data0, -data1};
819 Vc_INTRINSIC SimdArray
operator+()
const {
return *
this; }
821 Vc_INTRINSIC SimdArray operator~()
const
823 return {~data0, ~data1};
827 template <
typename U,
828 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
829 Vc_INTRINSIC Vc_CONST SimdArray
operator<<(U x)
const
831 return {data0 << x, data1 << x};
833 template <
typename U,
834 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
835 Vc_INTRINSIC SimdArray &operator<<=(U x)
841 template <
typename U,
842 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
843 Vc_INTRINSIC Vc_CONST SimdArray operator>>(U x)
const
845 return {data0 >> x, data1 >> x};
847 template <
typename U,
848 typename = enable_if<std::is_integral<T>::value && std::is_integral<U>::value>>
849 Vc_INTRINSIC SimdArray &operator>>=(U x)
857 #define Vc_BINARY_OPERATOR_(op) \
858 Vc_INTRINSIC Vc_CONST SimdArray operator op(const SimdArray &rhs) const \
860 return {data0 op rhs.data0, data1 op rhs.data1}; \
862 Vc_INTRINSIC SimdArray &operator op##=(const SimdArray &rhs) \
864 data0 op## = rhs.data0; \
865 data1 op## = rhs.data1; \
868 Vc_ALL_ARITHMETICS(Vc_BINARY_OPERATOR_);
869 Vc_ALL_BINARY(Vc_BINARY_OPERATOR_);
870 Vc_ALL_SHIFTS(Vc_BINARY_OPERATOR_);
871 #undef Vc_BINARY_OPERATOR_
873 #define Vc_COMPARES(op) \
874 Vc_INTRINSIC mask_type operator op(const SimdArray &rhs) const \
876 return {data0 op rhs.data0, data1 op rhs.data1}; \
878 Vc_ALL_COMPARES(Vc_COMPARES);
886 Vc_INTRINSIC alias_type &operator[](std::size_t index)
888 auto tmp =
reinterpret_cast<alias_type *
>(
this);
893 Vc_INTRINSIC value_type operator[](std::size_t index)
const
895 const auto tmp =
reinterpret_cast<const alias_type *
>(
this);
902 Vc_INTRINSIC Common::WriteMaskedVector<SimdArray, mask_type> operator()(
909 Vc_INTRINSIC
void assign(
const SimdArray &v,
const mask_type &k)
911 data0.assign(v.data0, internal_data0(k));
912 data1.assign(v.data1, internal_data1(k));
916 #define Vc_REDUCTION_FUNCTION_(name_, binary_fun_, scalar_fun_) \
918 template <typename ForSfinae = void> \
919 Vc_INTRINSIC enable_if<std::is_same<ForSfinae, void>::value && \
920 storage_type0::size() == storage_type1::size(), \
921 value_type> name_##_impl() const \
923 return binary_fun_(data0, data1).name_(); \
926 template <typename ForSfinae = void> \
927 Vc_INTRINSIC enable_if<std::is_same<ForSfinae, void>::value && \
928 storage_type0::size() != storage_type1::size(), \
929 value_type> name_##_impl() const \
931 return scalar_fun_(data0.name_(), data1.name_()); \
936 Vc_INTRINSIC value_type name_() const { return name_##_impl(); } \
938 Vc_INTRINSIC value_type name_(const mask_type &mask) const \
940 if (Vc_IS_UNLIKELY(Split::lo(mask).isEmpty())) { \
941 return data1.name_(Split::hi(mask)); \
942 } else if (Vc_IS_UNLIKELY(Split::hi(mask).isEmpty())) { \
943 return data0.name_(Split::lo(mask)); \
945 return scalar_fun_(data0.name_(Split::lo(mask)), \
946 data1.name_(Split::hi(mask))); \
949 Vc_NOTHING_EXPECTING_SEMICOLON
952 Vc_REDUCTION_FUNCTION_(product, internal::product_helper_, internal::product_helper_);
953 Vc_REDUCTION_FUNCTION_(sum, internal::sum_helper_, internal::sum_helper_);
954 #undef Vc_REDUCTION_FUNCTION_
955 Vc_INTRINSIC Vc_PURE SimdArray partialSum() const
958 auto ps0 = data0.partialSum();
960 tmp[0] += ps0[data0.size() - 1];
961 return {std::move(ps0), tmp.partialSum()};
966 template <
typename F> Vc_INTRINSIC SimdArray apply(F &&f)
const
968 return {data0.apply(f), data1.apply(f)};
971 template <
typename F> Vc_INTRINSIC SimdArray apply(F &&f,
const mask_type &k)
const
973 return {data0.apply(f, Split::lo(k)), data1.apply(f, Split::hi(k))};
978 inline SimdArray
shifted(
int amount)
const
980 constexpr
int SSize = Size;
981 constexpr
int SSize0 = storage_type0::Size;
982 constexpr
int SSize1 = storage_type1::Size;
987 if (amount > -SSize0) {
988 return {data0.shifted(amount), data1.shifted(amount, data0)};
990 if (amount == -SSize0) {
993 if (amount < -SSize0) {
999 if (amount >= SSize) {
1001 }
else if (amount >= SSize0) {
1005 }
else if (amount >= SSize1) {
1008 return {data0.shifted(amount, data1), data1.shifted(amount)};
1013 template <std::
size_t NN>
1015 !(std::is_same<storage_type0, storage_type1>::value &&
1020 constexpr
int SSize = Size;
1022 return SimdArray::generate([&](
int i) ->
value_type {
1025 return operator[](i);
1026 }
else if (i >= -SSize) {
1027 return shiftIn[i + SSize];
1032 return SimdArray::generate([&](
int i) ->
value_type {
1035 return operator[](i);
1036 }
else if (i < 2 * SSize) {
1037 return shiftIn[i - SSize];
1043 template <std::
size_t NN>
1045 enable_if<(std::is_same<storage_type0, storage_type1>::value &&
1050 constexpr
int SSize = Size;
1052 if (amount > -static_cast<int>(storage_type0::Size)) {
1053 return {data0.shifted(amount, internal_data1(shiftIn)),
1054 data1.shifted(amount, data0)};
1056 if (amount == -static_cast<int>(storage_type0::Size)) {
1057 return {storage_type0(internal_data1(shiftIn)), storage_type1(data0)};
1059 if (amount > -SSize) {
1061 internal_data1(shiftIn)
1062 .shifted(amount + static_cast<int>(storage_type0::Size), internal_data0(shiftIn)),
1063 data0.shifted(amount + static_cast<int>(storage_type0::Size), internal_data1(shiftIn))};
1065 if (amount == -SSize) {
1068 if (amount > -2 * SSize) {
1069 return shiftIn.shifted(amount + SSize);
1075 if (amount < static_cast<int>(storage_type0::Size)) {
1076 return {data0.shifted(amount, data1),
1077 data1.shifted(amount, internal_data0(shiftIn))};
1079 if (amount == static_cast<int>(storage_type0::Size)) {
1080 return {storage_type0(data1), storage_type1(internal_data0(shiftIn))};
1082 if (amount < SSize) {
1083 return {data1.shifted(amount - static_cast<int>(storage_type0::Size), internal_data0(shiftIn)),
1084 internal_data0(shiftIn)
1085 .shifted(amount - static_cast<int>(storage_type0::Size), internal_data1(shiftIn))};
1087 if (amount == SSize) {
1090 if (amount < 2 * SSize) {
1091 return shiftIn.shifted(amount - SSize);
1098 Vc_INTRINSIC SimdArray rotated(
int amount)
const
1100 amount %= int(size());
1103 }
else if (amount < 0) {
1107 auto &&d0cvtd =
simd_cast<storage_type1>(data0);
1108 auto &&d1cvtd =
simd_cast<storage_type0>(data1);
1109 constexpr
int size0 = storage_type0::size();
1110 constexpr
int size1 = storage_type1::size();
1112 if (amount == size0 && std::is_same<storage_type0, storage_type1>::value) {
1113 return {std::move(d1cvtd), std::move(d0cvtd)};
1114 }
else if (amount < size1) {
1115 return {data0.shifted(amount, d1cvtd), data1.shifted(amount, d0cvtd)};
1116 }
else if (amount == size1) {
1117 return {data0.shifted(amount, d1cvtd), std::move(d0cvtd)};
1118 }
else if (
int(size()) - amount < size1) {
1119 return {data0.shifted(amount -
int(size()), d1cvtd.shifted(size1 - size0)),
1120 data1.shifted(amount -
int(size()), data0.shifted(size0 - size1))};
1121 }
else if (
int(size()) - amount == size1) {
1122 return {data0.shifted(-size1, d1cvtd.shifted(size1 - size0)),
1123 simd_cast<storage_type1>(data0.shifted(size0 - size1))};
1124 }
else if (amount <= size0) {
1125 return {data0.shifted(size1, d1cvtd).shifted(amount - size1, data0),
1126 simd_cast<storage_type1>(data0.shifted(amount - size1))};
1128 return {data0.shifted(size1, d1cvtd).shifted(amount - size1, data0),
1129 simd_cast<storage_type1>(data0.shifted(amount - size1, d1cvtd))};
1136 Vc_INTRINSIC SimdArray interleaveLow(
const SimdArray &x)
const
1139 return {data0.interleaveLow(x.data0),
1140 simd_cast<storage_type1>(data0.interleaveHigh(x.data0))};
1143 Vc_INTRINSIC SimdArray interleaveHigh(
const SimdArray &x)
const
1145 return interleaveHighImpl(
1147 std::integral_constant<bool, storage_type0::Size == storage_type1::Size>());
1152 Vc_INTRINSIC SimdArray interleaveHighImpl(
const SimdArray &x, std::true_type)
const
1154 return {data1.interleaveLow(x.data1), data1.interleaveHigh(x.data1)};
1157 inline SimdArray interleaveHighImpl(
const SimdArray &x, std::false_type)
const
1159 return {data0.interleaveHigh(x.data0)
1160 .shifted(storage_type1::Size,
1161 simd_cast<storage_type0>(data1.interleaveLow(x.data1))),
1162 data1.interleaveHigh(x.data1)};
1167 inline SimdArray reversed() const
1169 if (std::is_same<storage_type0, storage_type1>::value) {
1170 return {
simd_cast<storage_type0>(data1).reversed(),
1171 simd_cast<storage_type1>(data0).reversed()};
1173 return {data0.shifted(storage_type1::Size, data1).reversed(),
1174 simd_cast<storage_type1>(data0.reversed().shifted(
1175 storage_type0::Size - storage_type1::Size))};
1179 inline SimdArray sorted() const
1182 std::integral_constant<bool, storage_type0::Size == storage_type1::Size>());
1186 Vc_INTRINSIC SimdArray sortedImpl(std::true_type)
const
1188 #ifdef Vc_DEBUG_SORTED
1189 std::cerr <<
"-- " << data0 << data1 <<
'\n';
1191 const auto a = data0.sorted();
1192 const auto b = data1.sorted().reversed();
1193 const auto lo =
Vc::min(a, b);
1194 const auto hi =
Vc::max(a, b);
1195 return {lo.sorted(), hi.sorted()};
1199 Vc_INTRINSIC SimdArray sortedImpl(std::false_type)
const
1201 using SortableArray = SimdArray<value_type, Common::nextPowerOfTwo(size())>;
1202 auto sortable =
simd_cast<SortableArray>(*this);
1203 for (std::size_t i = Size; i < SortableArray::Size; ++i) {
1204 using limits = std::numeric_limits<value_type>;
1205 if (limits::has_infinity) {
1206 sortable[i] = limits::infinity();
1211 return simd_cast<SimdArray>(sortable.sorted());
1245 static constexpr std::size_t Size = size();
1248 Vc_INTRINSIC Vc_DEPRECATED(
"use exponent(x) instead") SimdArray
exponent()
const
1254 Vc_INTRINSIC Vc_DEPRECATED(
"use isnegative(x) instead") MaskType isNegative()
const
1260 Vc_INTRINSIC Vc_DEPRECATED(
"use copysign(x, y) instead") SimdArray
1261 copySign(const SimdArray &reference)
const
1269 friend storage_type0 &internal_data0<>(SimdArray &x);
1270 friend storage_type1 &internal_data1<>(SimdArray &x);
1271 friend const storage_type0 &internal_data0<>(
const SimdArray &x);
1272 friend const storage_type1 &internal_data1<>(
const SimdArray &x);
1275 Vc_INTRINSIC SimdArray(storage_type0 &&x, storage_type1 &&y)
1276 : data0(
std::move(x)), data1(
std::move(y))
1280 Vc_FREE_STORE_OPERATORS_ALIGNED(
alignof(storage_type0));
1283 storage_type0 data0;
1284 storage_type1 data1;
1286 #undef Vc_CURRENT_CLASS_NAME
1287 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1288 constexpr std::size_t SimdArray<T, N, V, M>::Size;
1289 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1293 template <
typename T, std::
size_t N,
typename VectorType, std::
size_t M>
1294 template <
typename MT,
typename IT>
1295 inline void SimdArray<T, N, VectorType, M>::gatherImplementation(
const MT *mem,
1298 data0.gather(mem, Split::lo(Common::Operations::gather(),
1301 data1.gather(mem, Split::hi(Common::Operations::gather(), std::forward<IT>(indexes)));
1303 template <
typename T, std::
size_t N,
typename VectorType, std::
size_t M>
1304 template <
typename MT,
typename IT>
1305 inline void SimdArray<T, N, VectorType, M>::gatherImplementation(
const MT *mem,
1306 IT &&indexes, MaskArgument mask)
1308 data0.gather(mem, Split::lo(Common::Operations::gather(), indexes),
1311 data1.gather(mem, Split::hi(Common::Operations::gather(), std::forward<IT>(indexes)),
1317 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1318 Vc_INTRINSIC
typename SimdArrayTraits<T, N>::storage_type0 &internal_data0(
1319 SimdArray<T, N, V, M> &x)
1324 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1325 Vc_INTRINSIC
typename SimdArrayTraits<T, N>::storage_type1 &internal_data1(
1326 SimdArray<T, N, V, M> &x)
1331 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1332 Vc_INTRINSIC
const typename SimdArrayTraits<T, N>::storage_type0 &internal_data0(
1333 const SimdArray<T, N, V, M> &x)
1338 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
1339 Vc_INTRINSIC
const typename SimdArrayTraits<T, N>::storage_type1 &internal_data1(
1340 const SimdArray<T, N, V, M> &x)
1346 namespace result_vector_type_internal
1348 template <
typename T>
1349 using type =
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
1351 template <
typename T>
1352 using is_integer_larger_than_int = std::integral_constant<
1353 bool, std::is_integral<T>::value &&(
sizeof(T) >
sizeof(
int) ||
1354 std::is_same<T, long>::value ||
1355 std::is_same<T, unsigned long>::value)>;
1358 typename L,
typename R,
1359 std::size_t N = Traits::isSimdArray<L>::value ? Traits::simd_vector_size<L>::value
1360 : Traits::simd_vector_size<R>::value,
1362 (Traits::isSimdArray<L>::value ||
1363 Traits::isSimdArray<R>::value)
1364 && !std::is_same<type<L>, type<R>>::value
1367 ((std::is_arithmetic<type<L>>::value &&
1368 !is_integer_larger_than_int<type<L>>::value) ||
1369 (std::is_arithmetic<type<R>>::value &&
1370 !is_integer_larger_than_int<type<R>>::value)
1375 Traits::simd_vector_size<L>::value == Traits::simd_vector_size<R>::value &&
1376 ((Traits::is_simd_vector<L>::value && !Traits::isSimdArray<L>::value) ||
1377 (Traits::is_simd_vector<R>::value && !Traits::isSimdArray<R>::value))))>
1380 template <
typename L,
typename R, std::
size_t N>
struct evaluate<L, R, N, true>
1383 using LScalar = Traits::entry_type_of<L>;
1384 using RScalar = Traits::entry_type_of<R>;
1386 template <
bool B,
typename True,
typename False>
1387 using conditional =
typename std::conditional<B, True, False>::type;
1400 using type = SimdArray<
1401 conditional<(std::is_integral<LScalar>::value &&std::is_integral<RScalar>::value &&
1402 sizeof(LScalar) <
sizeof(
int) &&
1403 sizeof(RScalar) <
sizeof(
int)),
1404 conditional<(
sizeof(LScalar) ==
sizeof(RScalar)),
1405 conditional<std::is_unsigned<LScalar>::value, LScalar, RScalar>,
1406 conditional<(sizeof(LScalar) >
sizeof(RScalar)), LScalar, RScalar>>,
1407 decltype(std::declval<LScalar>() + std::declval<RScalar>())>,
1413 template <
typename L,
typename R>
1414 using result_vector_type =
typename result_vector_type_internal::evaluate<L, R>::type;
1419 "result_vector_type does not work");
1421 #define Vc_BINARY_OPERATORS_(op_) \
1423 template <typename L, typename R> \
1424 Vc_INTRINSIC result_vector_type<L, R> operator op_(L &&lhs, R &&rhs) \
1426 using Return = result_vector_type<L, R>; \
1427 return Return(std::forward<L>(lhs)) op_ Return(std::forward<R>(rhs)); \
1446 Vc_ALL_ARITHMETICS(Vc_BINARY_OPERATORS_);
1448 Vc_ALL_BINARY(Vc_BINARY_OPERATORS_);
1450 #undef Vc_BINARY_OPERATORS_
1451 #define Vc_BINARY_OPERATORS_(op_) \
1453 template <typename L, typename R> \
1454 Vc_INTRINSIC typename result_vector_type<L, R>::mask_type operator op_(L &&lhs, \
1457 using Promote = result_vector_type<L, R>; \
1458 return Promote(std::forward<L>(lhs)) op_ Promote(std::forward<R>(rhs)); \
1477 Vc_ALL_COMPARES(Vc_BINARY_OPERATORS_);
1480 #undef Vc_BINARY_OPERATORS_
1483 #define Vc_FORWARD_UNARY_OPERATOR(name_) \
1485 template <typename T, std::size_t N, typename V, std::size_t M> \
1486 inline SimdArray<T, N, V, M> name_(const SimdArray<T, N, V, M> &x) \
1488 return SimdArray<T, N, V, M>::fromOperation( \
1489 Common::Operations::Forward_##name_(), x); \
1491 Vc_NOTHING_EXPECTING_SEMICOLON
1493 #define Vc_FORWARD_UNARY_BOOL_OPERATOR(name_) \
1495 template <typename T, std::size_t N, typename V, std::size_t M> \
1496 inline SimdMaskArray<T, N, V, M> name_(const SimdArray<T, N, V, M> &x) \
1498 return SimdMaskArray<T, N, V, M>::fromOperation( \
1499 Common::Operations::Forward_##name_(), x); \
1501 Vc_NOTHING_EXPECTING_SEMICOLON
1503 #define Vc_FORWARD_BINARY_OPERATOR(name_) \
1505 template <typename T, std::size_t N, typename V, std::size_t M> \
1506 inline SimdArray<T, N, V, M> name_(const SimdArray<T, N, V, M> &x, \
1507 const SimdArray<T, N, V, M> &y) \
1509 return SimdArray<T, N, V, M>::fromOperation( \
1510 Common::Operations::Forward_##name_(), x, y); \
1512 Vc_NOTHING_EXPECTING_SEMICOLON
1518 Vc_FORWARD_UNARY_OPERATOR(
abs);
1525 Vc_FORWARD_UNARY_OPERATOR(
cos);
1526 Vc_FORWARD_UNARY_OPERATOR(
exp);
1527 Vc_FORWARD_UNARY_OPERATOR(
exponent);
1530 template <
typename T, std::
size_t N>
1537 Vc_FORWARD_UNARY_BOOL_OPERATOR(
isinf);
1538 Vc_FORWARD_UNARY_BOOL_OPERATOR(
isnan);
1541 template <
typename T, std::
size_t N>
1547 template <
typename T, std::
size_t N>
1548 SimdArray<T, N>
ldexp(
const SimdArray<T, N> &x,
const SimdArray<int, N> &e)
1552 Vc_FORWARD_UNARY_OPERATOR(
log);
1556 Vc_FORWARD_UNARY_OPERATOR(
round);
1557 Vc_FORWARD_UNARY_OPERATOR(
rsqrt);
1558 Vc_FORWARD_UNARY_OPERATOR(
sin);
1560 template <
typename T, std::
size_t N>
1566 Vc_FORWARD_UNARY_OPERATOR(
trunc);
1567 Vc_FORWARD_BINARY_OPERATOR(
min);
1568 Vc_FORWARD_BINARY_OPERATOR(
max);
1570 #undef Vc_FORWARD_UNARY_OPERATOR
1571 #undef Vc_FORWARD_UNARY_BOOL_OPERATOR
1572 #undef Vc_FORWARD_BINARY_OPERATOR
1579 template <
typename Return, std::size_t N,
typename T,
typename... From>
1580 Vc_INTRINSIC Vc_CONST enable_if<
sizeof...(From) != 0, Return>
1581 simd_cast_impl_smaller_input(
const From &... xs,
const T &last)
1584 for (
size_t i = 0; i < N; ++i) {
1585 r[i + N *
sizeof...(From)] = static_cast<typename Return::EntryType>(last[i]);
1589 template <
typename Return, std::
size_t N,
typename T>
1590 Vc_INTRINSIC Vc_CONST Return simd_cast_impl_smaller_input(
const T &last)
1592 Return r = Return();
1593 for (
size_t i = 0; i < N; ++i) {
1594 r[i] =
static_cast<typename Return::EntryType
>(last[i]);
1598 template <
typename Return, std::size_t N,
typename T,
typename... From>
1599 Vc_INTRINSIC Vc_CONST enable_if<
sizeof...(From) != 0, Return> simd_cast_impl_larger_input(
1600 const From &... xs,
const T &last)
1603 for (
size_t i = N *
sizeof...(From); i < Return::Size; ++i) {
1604 r[i] =
static_cast<typename Return::EntryType
>(last[i - N *
sizeof...(From)]);
1608 template <
typename Return, std::
size_t N,
typename T>
1609 Vc_INTRINSIC Vc_CONST Return simd_cast_impl_larger_input(
const T &last)
1611 Return r = Return();
1612 for (
size_t i = 0; i < Return::size(); ++i) {
1613 r[i] =
static_cast<typename Return::EntryType
>(last[i]);
1619 template <
typename Return,
typename T,
typename... From>
1620 Vc_INTRINSIC_L Vc_CONST_L Return
1621 simd_cast_without_last(
const From &... xs,
const T &) Vc_INTRINSIC_R Vc_CONST_R;
1624 template <typename... Ts> struct are_all_types_equal;
1625 template <typename T>
1626 struct are_all_types_equal<T> : public
std::integral_constant<
bool, true>
1629 template <
typename T0,
typename T1,
typename... Ts>
1630 struct are_all_types_equal<T0, T1, Ts...>
1631 :
public std::integral_constant<
1632 bool, std::is_same<T0, T1>::value && are_all_types_equal<T1, Ts...>::value>
1656 template <
typename Return,
typename... Ts>
1657 Vc_INTRINSIC Vc_CONST Return
1658 simd_cast_interleaved_argument_order(
const Ts &... a,
const Ts &... b);
1662 template <
typename Return, std::size_t offset,
typename From,
typename... Froms>
1663 Vc_INTRINSIC Vc_CONST
1664 enable_if<(are_all_types_equal<From, Froms...>::value && offset == 0), Return>
1665 simd_cast_with_offset(
const From &x,
const Froms &... xs);
1667 template <
typename Return, std::
size_t offset,
typename From>
1668 Vc_INTRINSIC Vc_CONST
1669 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size == 0), Return>
1670 simd_cast_with_offset(
const From &x);
1672 template <
typename Return, std::
size_t offset,
typename From>
1673 Vc_INTRINSIC Vc_CONST
1674 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size != 0 &&
1675 ((Traits::isSimdArray<Return>::value &&
1676 !Traits::isAtomicSimdArray<Return>::value) ||
1677 (Traits::isSimdMaskArray<Return>::value &&
1678 !Traits::isAtomicSimdMaskArray<Return>::value))),
1680 simd_cast_with_offset(
const From &x);
1682 template <
typename Return, std::
size_t offset,
typename From>
1683 Vc_INTRINSIC Vc_CONST
1684 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size != 0 &&
1685 ((Traits::isSimdArray<Return>::value &&
1686 Traits::isAtomicSimdArray<Return>::value) ||
1687 (Traits::isSimdMaskArray<Return>::value &&
1688 Traits::isAtomicSimdMaskArray<Return>::value))),
1690 simd_cast_with_offset(
const From &x);
1692 template <
typename Return, std::size_t offset,
typename From,
typename... Froms>
1693 Vc_INTRINSIC Vc_CONST enable_if<
1694 (are_all_types_equal<From, Froms...>::value && From::Size <= offset), Return>
1695 simd_cast_with_offset(
const From &,
const Froms &... xs)
1697 return simd_cast_with_offset<Return, offset - From::Size>(xs...);
1701 template <
typename Return, std::
size_t offset,
typename From>
1702 Vc_INTRINSIC Vc_CONST enable_if<(From::Size <= offset), Return> simd_cast_with_offset(
1709 template <
typename T,
typename... Ts>
struct first_type_of_impl
1713 template <
typename... Ts>
using first_type_of =
typename first_type_of_impl<Ts...>::type;
1716 template <
typename Return,
typename From>
1717 Vc_INTRINSIC Vc_CONST Return simd_cast_drop_arguments(From x);
1718 template <
typename Return,
typename... Froms>
1719 Vc_INTRINSIC Vc_CONST
1720 enable_if<(are_all_types_equal<Froms...>::value &&
1721 sizeof...(Froms) * first_type_of<Froms...>::Size < Return::Size),
1723 simd_cast_drop_arguments(Froms... xs, first_type_of<Froms...> x);
1727 template <
typename Return,
typename From,
typename... Froms>
1728 Vc_INTRINSIC Vc_CONST enable_if<
1729 (are_all_types_equal<From, Froms...>::value &&
1730 (1 +
sizeof...(Froms)) * From::Size >= Return::Size &&
sizeof...(Froms) != 0),
1732 simd_cast_drop_arguments(Froms... xs, From x, From);
1733 template <
typename Return,
typename From>
1734 Vc_INTRINSIC Vc_CONST
1735 enable_if<(are_all_types_equal<From>::value && From::Size >= Return::Size), Return>
1736 simd_cast_drop_arguments(From x, From);
1740 #ifdef Vc_DEBUG_SIMD_CAST
1741 void debugDoNothing(
const std::initializer_list<void *> &) {}
1742 template <
typename T0,
typename... Ts>
1743 inline void vc_debug_(
const char *prefix,
const char *suffix,
const T0 &arg0,
1746 std::cerr << prefix << arg0;
1747 debugDoNothing({&(std::cerr <<
", " << args)...});
1748 std::cerr << suffix;
1751 template <
typename T0,
typename... Ts>
1752 Vc_INTRINSIC
void vc_debug_(
const char *,
const char *,
const T0 &,
const Ts &...)
1759 #define Vc_SIMDARRAY_CASTS(SimdArrayType_, trait_name_) \
1760 template <typename Return, typename From, typename... Froms> \
1761 Vc_INTRINSIC Vc_CONST enable_if<(Traits::isAtomic##SimdArrayType_<Return>::value && \
1762 !Traits::is##SimdArrayType_<From>::value && \
1763 Traits::is_simd_##trait_name_<From>::value && \
1764 From::Size * sizeof...(Froms) < Return::Size && \
1765 are_all_types_equal<From, Froms...>::value), \
1767 simd_cast(From x, Froms... xs) \
1769 vc_debug_("simd_cast{1}(", ")\n", x, xs...); \
1770 return {simd_cast<typename Return::storage_type>(x, xs...)}; \
1772 template <typename Return, typename From, typename... Froms> \
1773 Vc_INTRINSIC Vc_CONST enable_if<(Traits::isAtomic##SimdArrayType_<Return>::value && \
1774 !Traits::is##SimdArrayType_<From>::value && \
1775 Traits::is_simd_##trait_name_<From>::value && \
1776 From::Size * sizeof...(Froms) >= Return::Size && \
1777 are_all_types_equal<From, Froms...>::value), \
1779 simd_cast(From x, Froms... xs) \
1781 vc_debug_("simd_cast{2}(", ")\n", x, xs...); \
1782 return {simd_cast_without_last<Return, From, Froms...>(x, xs...)}; \
1784 template <typename Return, typename From, typename... Froms> \
1785 Vc_INTRINSIC Vc_CONST enable_if<(Traits::is##SimdArrayType_<Return>::value && \
1786 !Traits::isAtomic##SimdArrayType_<Return>::value && \
1787 !Traits::is##SimdArrayType_<From>::value && \
1788 Traits::is_simd_##trait_name_<From>::value && \
1789 Common::left_size(Return::Size) < \
1790 From::Size * (1 + sizeof...(Froms)) && \
1791 are_all_types_equal<From, Froms...>::value), \
1793 simd_cast(From x, Froms... xs) \
1795 vc_debug_("simd_cast{3}(", ")\n", x, xs...); \
1796 using R0 = typename Return::storage_type0; \
1797 using R1 = typename Return::storage_type1; \
1798 return {simd_cast_drop_arguments<R0, Froms...>(x, xs...), \
1799 simd_cast_with_offset<R1, R0::Size>(x, xs...)}; \
1801 template <typename Return, typename From, typename... Froms> \
1802 Vc_INTRINSIC Vc_CONST enable_if<(Traits::is##SimdArrayType_<Return>::value && \
1803 !Traits::isAtomic##SimdArrayType_<Return>::value && \
1804 !Traits::is##SimdArrayType_<From>::value && \
1805 Traits::is_simd_##trait_name_<From>::value && \
1806 Common::left_size(Return::Size) >= \
1807 From::Size * (1 + sizeof...(Froms)) && \
1808 are_all_types_equal<From, Froms...>::value), \
1810 simd_cast(From x, Froms... xs) \
1812 vc_debug_("simd_cast{4}(", ")\n", x, xs...); \
1813 using R0 = typename Return::storage_type0; \
1814 using R1 = typename Return::storage_type1; \
1815 return {simd_cast<R0>(x, xs...), R1::Zero()}; \
1817 Vc_NOTHING_EXPECTING_SEMICOLON
1818 Vc_SIMDARRAY_CASTS(SimdArray,
vector);
1819 Vc_SIMDARRAY_CASTS(SimdMaskArray, mask);
1820 #undef Vc_SIMDARRAY_CASTS
1823 #define Vc_SIMDARRAY_CASTS(SimdArrayType_, trait_name_) \
1825 template <typename Return, int offset, typename From> \
1826 Vc_INTRINSIC Vc_CONST enable_if<(Traits::isAtomic##SimdArrayType_<Return>::value && \
1827 !Traits::is##SimdArrayType_<From>::value && \
1828 Traits::is_simd_##trait_name_<From>::value), \
1832 vc_debug_("simd_cast{offset, atomic}(", ")\n", offset, x); \
1833 return {simd_cast<typename Return::storage_type, offset>(x)}; \
1836 template <typename Return, int offset, typename From> \
1837 Vc_INTRINSIC Vc_CONST enable_if< \
1838 (Traits::is##SimdArrayType_<Return>::value && \
1839 !Traits::isAtomic##SimdArrayType_<Return>::value && \
1840 !Traits::is##SimdArrayType_<From>::value && \
1841 Traits::is_simd_##trait_name_<From>::value && \
1842 Return::Size * offset + Common::left_size(Return::Size) < From::Size), \
1846 vc_debug_("simd_cast{offset, split Return}(", ")\n", offset, x); \
1847 using R0 = typename Return::storage_type0; \
1848 constexpr int entries_offset = offset * Return::Size; \
1849 constexpr int entries_offset_right = entries_offset + R0::Size; \
1851 simd_cast_with_offset<typename Return::storage_type0, entries_offset>(x), \
1852 simd_cast_with_offset<typename Return::storage_type1, entries_offset_right>( \
1857 template <typename Return, int offset, typename From> \
1858 Vc_INTRINSIC Vc_CONST enable_if< \
1859 (Traits::is##SimdArrayType_<Return>::value && \
1860 !Traits::isAtomic##SimdArrayType_<Return>::value && \
1861 !Traits::is##SimdArrayType_<From>::value && \
1862 Traits::is_simd_##trait_name_<From>::value && \
1863 Return::Size * offset + Common::left_size(Return::Size) >= From::Size), \
1867 vc_debug_("simd_cast{offset, R1::Zero}(", ")\n", offset, x); \
1868 using R0 = typename Return::storage_type0; \
1869 using R1 = typename Return::storage_type1; \
1870 constexpr int entries_offset = offset * Return::Size; \
1871 return {simd_cast_with_offset<R0, entries_offset>(x), R1::Zero()}; \
1873 Vc_NOTHING_EXPECTING_SEMICOLON
1874 Vc_SIMDARRAY_CASTS(SimdArray,
vector);
1875 Vc_SIMDARRAY_CASTS(SimdMaskArray, mask);
1876 #undef Vc_SIMDARRAY_CASTS
1879 #define Vc_SIMDARRAY_CASTS(SimdArrayType_) \
1881 template <typename Return, typename T, std::size_t N, typename V, typename... From> \
1882 Vc_INTRINSIC Vc_CONST \
1883 enable_if<(are_all_types_equal<SimdArrayType_<T, N, V, N>, From...>::value && \
1884 (sizeof...(From) == 0 || N * sizeof...(From) < Return::Size) && \
1885 !std::is_same<Return, SimdArrayType_<T, N, V, N>>::value), \
1887 simd_cast(const SimdArrayType_<T, N, V, N> &x0, const From &... xs) \
1889 vc_debug_("simd_cast{indivisible}(", ")\n", x0, xs...); \
1890 return simd_cast<Return>(internal_data(x0), internal_data(xs)...); \
1893 template <typename Return, typename T, std::size_t N, typename V, typename... From> \
1894 Vc_INTRINSIC Vc_CONST \
1895 enable_if<(are_all_types_equal<SimdArrayType_<T, N, V, N>, From...>::value && \
1896 (sizeof...(From) > 0 && (N * sizeof...(From) >= Return::Size)) && \
1897 !std::is_same<Return, SimdArrayType_<T, N, V, N>>::value), \
1899 simd_cast(const SimdArrayType_<T, N, V, N> &x0, const From &... xs) \
1901 vc_debug_("simd_cast{indivisible2}(", ")\n", x0, xs...); \
1902 return simd_cast_without_last<Return, \
1903 typename SimdArrayType_<T, N, V, N>::storage_type, \
1904 typename From::storage_type...>( \
1905 internal_data(x0), internal_data(xs)...); \
1908 template <typename Return, typename T, std::size_t N, typename V, std::size_t M, \
1910 Vc_INTRINSIC Vc_CONST enable_if< \
1911 (N != M && are_all_types_equal<SimdArrayType_<T, N, V, M>, From...>::value && \
1912 N * sizeof...(From) < Return::Size && ((N - 1) & N) == 0), \
1914 simd_cast(const SimdArrayType_<T, N, V, M> &x0, const From &... xs) \
1916 vc_debug_("simd_cast{bisectable}(", ")\n", x0, xs...); \
1917 return simd_cast_interleaved_argument_order< \
1918 Return, typename SimdArrayType_<T, N, V, M>::storage_type0, \
1919 typename From::storage_type0...>(internal_data0(x0), internal_data0(xs)..., \
1920 internal_data1(x0), internal_data1(xs)...); \
1924 template <typename Return, typename T, std::size_t N, typename V, std::size_t M, \
1926 Vc_INTRINSIC Vc_CONST enable_if< \
1927 (N != M && are_all_types_equal<SimdArrayType_<T, N, V, M>, From...>::value && \
1928 N * sizeof...(From) >= Return::Size && ((N - 1) & N) == 0), \
1930 simd_cast(const SimdArrayType_<T, N, V, M> &x0, const From &... xs) \
1932 vc_debug_("simd_cast{bisectable2}(", ")\n", x0, xs...); \
1933 return simd_cast_without_last<Return, SimdArrayType_<T, N, V, M>, From...>( \
1937 template <typename Return, typename T, std::size_t N, typename V, std::size_t M, \
1939 Vc_INTRINSIC Vc_CONST enable_if< \
1940 (N != M && are_all_types_equal<SimdArrayType_<T, N, V, M>, From...>::value && \
1941 N * (1 + sizeof...(From)) <= Return::Size && ((N - 1) & N) != 0), \
1943 simd_cast(const SimdArrayType_<T, N, V, M> &x0, const From &... xs) \
1945 vc_debug_("simd_cast{remaining}(", ")\n", x0, xs...); \
1946 return simd_cast_impl_smaller_input<Return, N, SimdArrayType_<T, N, V, M>, \
1947 From...>(x0, xs...); \
1950 template <typename Return, typename T, std::size_t N, typename V, std::size_t M, \
1952 Vc_INTRINSIC Vc_CONST enable_if< \
1953 (N != M && are_all_types_equal<SimdArrayType_<T, N, V, M>, From...>::value && \
1954 N * (1 + sizeof...(From)) > Return::Size && ((N - 1) & N) != 0), \
1956 simd_cast(const SimdArrayType_<T, N, V, M> &x0, const From &... xs) \
1958 vc_debug_("simd_cast{remaining2}(", ")\n", x0, xs...); \
1959 return simd_cast_impl_larger_input<Return, N, SimdArrayType_<T, N, V, M>, \
1960 From...>(x0, xs...); \
1963 template <typename Return, typename T, std::size_t N, typename V, std::size_t M> \
1964 Vc_INTRINSIC Vc_CONST \
1965 enable_if<(N != M && N >= 2 * Return::Size && ((N - 1) & N) == 0), Return> \
1966 simd_cast(const SimdArrayType_<T, N, V, M> &x) \
1968 vc_debug_("simd_cast{single bisectable}(", ")\n", x); \
1969 return simd_cast<Return>(internal_data0(x)); \
1971 template <typename Return, typename T, std::size_t N, typename V, std::size_t M> \
1972 Vc_INTRINSIC Vc_CONST enable_if<(N != M && N > Return::Size && \
1973 N < 2 * Return::Size && ((N - 1) & N) == 0), \
1975 simd_cast(const SimdArrayType_<T, N, V, M> &x) \
1977 vc_debug_("simd_cast{single bisectable2}(", ")\n", x); \
1978 return simd_cast<Return>(internal_data0(x), internal_data1(x)); \
1980 Vc_NOTHING_EXPECTING_SEMICOLON
1981 Vc_SIMDARRAY_CASTS(SimdArray);
1982 Vc_SIMDARRAY_CASTS(SimdMaskArray);
1983 #undef Vc_SIMDARRAY_CASTS
1986 #define Vc_SIMDARRAY_CASTS(SimdArrayType_) \
1988 template <typename Return, int offset, typename T, std::size_t N, typename V, \
1990 Vc_INTRINSIC Vc_CONST enable_if<(offset == 0), Return> simd_cast( \
1991 const SimdArrayType_<T, N, V, M> &x) \
1993 vc_debug_("simd_cast{offset == 0}(", ")\n", offset, x); \
1994 return simd_cast<Return>(x); \
1997 template <typename Return, int offset, typename T, std::size_t N, typename V> \
1998 Vc_INTRINSIC Vc_CONST enable_if<(offset != 0), Return> simd_cast( \
1999 const SimdArrayType_<T, N, V, N> &x) \
2001 vc_debug_("simd_cast{offset, forward}(", ")\n", offset, x); \
2002 return simd_cast<Return, offset>(internal_data(x)); \
2005 template <typename Return, int offset, typename T, std::size_t N, typename V, \
2007 Vc_INTRINSIC Vc_CONST \
2008 enable_if<(N != M && offset * Return::Size >= Common::left_size(N) && \
2009 offset != 0 && Common::left_size(N) % Return::Size == 0), \
2011 simd_cast(const SimdArrayType_<T, N, V, M> &x) \
2013 vc_debug_("simd_cast{offset, right}(", ")\n", offset, x); \
2014 return simd_cast<Return, offset - Common::left_size(N) / Return::Size>( \
2015 internal_data1(x)); \
2019 template <typename Return, int offset, typename T, std::size_t N, typename V, \
2021 Vc_INTRINSIC Vc_CONST \
2022 enable_if<(N != M && offset * Return::Size >= Common::left_size(N) && \
2023 offset != 0 && Common::left_size(N) % Return::Size != 0), \
2025 simd_cast(const SimdArrayType_<T, N, V, M> &x) \
2027 vc_debug_("simd_cast{offset, right, nofit}(", ")\n", offset, x); \
2028 return simd_cast_with_offset<Return, \
2029 offset * Return::Size - Common::left_size(N)>( \
2030 internal_data1(x)); \
2033 template <typename Return, int offset, typename T, std::size_t N, typename V, \
2035 Vc_INTRINSIC Vc_CONST \
2036 enable_if<(N != M && \
2037 offset != 0 && (offset + 1) * Return::Size <= Common::left_size(N)), \
2039 simd_cast(const SimdArrayType_<T, N, V, M> &x) \
2041 vc_debug_("simd_cast{offset, left}(", ")\n", offset, x); \
2042 return simd_cast<Return, offset>(internal_data0(x)); \
2045 template <typename Return, int offset, typename T, std::size_t N, typename V, \
2047 Vc_INTRINSIC Vc_CONST \
2048 enable_if<(N != M && (offset * Return::Size < Common::left_size(N)) && \
2049 offset != 0 && (offset + 1) * Return::Size > Common::left_size(N)), \
2051 simd_cast(const SimdArrayType_<T, N, V, M> &x) \
2053 vc_debug_("simd_cast{offset, copy scalars}(", ")\n", offset, x); \
2054 using R = typename Return::EntryType; \
2055 Return r = Return::Zero(); \
2056 for (std::size_t i = offset * Return::Size; \
2057 i < std::min(N, (offset + 1) * Return::Size); ++i) { \
2058 r[i - offset * Return::Size] = static_cast<R>(x[i]); \
2062 Vc_NOTHING_EXPECTING_SEMICOLON
2063 Vc_SIMDARRAY_CASTS(SimdArray);
2064 Vc_SIMDARRAY_CASTS(SimdMaskArray);
2065 #undef Vc_SIMDARRAY_CASTS
2067 template <
typename Return,
typename From>
2068 Vc_INTRINSIC Vc_CONST Return simd_cast_drop_arguments(From x)
2072 template <
typename Return,
typename... Froms>
2073 Vc_INTRINSIC Vc_CONST
2074 enable_if<(are_all_types_equal<Froms...>::value &&
2075 sizeof...(Froms) * first_type_of<Froms...>::Size < Return::Size),
2077 simd_cast_drop_arguments(Froms... xs, first_type_of<Froms...> x)
2084 template <
typename Return,
typename From,
typename... Froms>
2085 Vc_INTRINSIC Vc_CONST enable_if<
2086 (are_all_types_equal<From, Froms...>::value &&
2087 (1 +
sizeof...(Froms)) * From::Size >= Return::Size &&
sizeof...(Froms) != 0),
2089 simd_cast_drop_arguments(Froms... xs, From x, From)
2091 return simd_cast_drop_arguments<Return, Froms...>(xs..., x);
2093 template <
typename Return,
typename From>
2094 Vc_INTRINSIC Vc_CONST
2095 enable_if<(are_all_types_equal<From>::value && From::Size >= Return::Size), Return>
2096 simd_cast_drop_arguments(From x, From)
2098 return simd_cast_drop_arguments<Return>(x);
2102 template <
typename Return, std::
size_t offset,
typename From>
2103 Vc_INTRINSIC Vc_CONST
2104 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size == 0),
2105 Return> simd_cast_with_offset(
const From &x)
2107 return simd_cast<Return, offset / Return::Size>(x);
2109 template <
typename Return, std::
size_t offset,
typename From>
2110 Vc_INTRINSIC Vc_CONST
2111 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size != 0 &&
2112 ((Traits::isSimdArray<Return>::value &&
2113 !Traits::isAtomicSimdArray<Return>::value) ||
2114 (Traits::isSimdMaskArray<Return>::value &&
2115 !Traits::isAtomicSimdMaskArray<Return>::value))),
2117 simd_cast_with_offset(
const From &x)
2119 using R0 =
typename Return::storage_type0;
2120 using R1 =
typename Return::storage_type1;
2121 return {simd_cast_with_offset<R0, offset>(x),
2122 simd_cast_with_offset<R1, offset + R0::Size>(x)};
2124 template <
typename Return, std::
size_t offset,
typename From>
2125 Vc_INTRINSIC Vc_CONST
2126 enable_if<(From::Size > offset && offset > 0 && offset % Return::Size != 0 &&
2127 ((Traits::isSimdArray<Return>::value &&
2128 Traits::isAtomicSimdArray<Return>::value) ||
2129 (Traits::isSimdMaskArray<Return>::value &&
2130 Traits::isAtomicSimdMaskArray<Return>::value))),
2132 simd_cast_with_offset(
const From &x)
2134 return simd_cast<Return, offset / Return::Size>(x.shifted(offset % Return::Size));
2136 template <
typename Return, std::size_t offset,
typename From,
typename... Froms>
2137 Vc_INTRINSIC Vc_CONST
2138 enable_if<(are_all_types_equal<From, Froms...>::value && offset == 0), Return>
2139 simd_cast_with_offset(
const From &x,
const Froms &... xs)
2145 template <
typename Return,
typename T,
typename... From>
2146 Vc_INTRINSIC Vc_CONST Return simd_cast_without_last(
const From &... xs,
const T &)
2154 template <std::size_t I,
typename T0,
typename... Ts>
2155 Vc_INTRINSIC Vc_CONST enable_if<(I == 0), T0> extract_interleaved(
const T0 &a0,
2163 template <std::size_t I,
typename T0,
typename... Ts>
2164 Vc_INTRINSIC Vc_CONST enable_if<(I == 1), T0> extract_interleaved(
const T0 &,
2172 template <std::size_t I,
typename T0,
typename... Ts>
2173 Vc_INTRINSIC Vc_CONST enable_if<(I > 1), T0> extract_interleaved(
const T0 &,
2178 return extract_interleaved<I - 2, Ts...>(a..., b...);
2182 template <
typename Return,
typename... Ts, std::size_t... Indexes>
2183 Vc_INTRINSIC Vc_CONST Return
2184 simd_cast_interleaved_argument_order_1(index_sequence<Indexes...>,
const Ts &... a,
2187 return simd_cast<Return>(extract_interleaved<Indexes, Ts...>(a..., b...)...);
2191 template <
typename Return,
typename... Ts>
2192 Vc_INTRINSIC Vc_CONST Return
2193 simd_cast_interleaved_argument_order(
const Ts &... a,
const Ts &... b)
2195 using seq = make_index_sequence<
sizeof...(Ts)*2>;
2196 return simd_cast_interleaved_argument_order_1<Return, Ts...>(seq(), a..., b...);
2200 #define Vc_CONDITIONAL_ASSIGN(name_, op_) \
2201 template <Operator O, typename T, std::size_t N, typename V, size_t VN, typename M, \
2203 Vc_INTRINSIC enable_if<O == Operator::name_, void> conditional_assign( \
2204 SimdArray<T, N, V, VN> &lhs, M &&mask, U &&rhs) \
2206 lhs(mask) op_ rhs; \
2208 Vc_NOTHING_EXPECTING_SEMICOLON
2209 Vc_CONDITIONAL_ASSIGN( Assign, =);
2210 Vc_CONDITIONAL_ASSIGN( PlusAssign, +=);
2211 Vc_CONDITIONAL_ASSIGN( MinusAssign, -=);
2212 Vc_CONDITIONAL_ASSIGN( MultiplyAssign, *=);
2213 Vc_CONDITIONAL_ASSIGN( DivideAssign, /=);
2214 Vc_CONDITIONAL_ASSIGN( RemainderAssign, %=);
2215 Vc_CONDITIONAL_ASSIGN( XorAssign, ^=);
2216 Vc_CONDITIONAL_ASSIGN( AndAssign, &=);
2217 Vc_CONDITIONAL_ASSIGN( OrAssign, |=);
2218 Vc_CONDITIONAL_ASSIGN( LeftShiftAssign,<<=);
2219 Vc_CONDITIONAL_ASSIGN(RightShiftAssign,>>=);
2220 #undef Vc_CONDITIONAL_ASSIGN
2222 #define Vc_CONDITIONAL_ASSIGN(name_, expr_) \
2223 template <Operator O, typename T, std::size_t N, typename V, size_t VN, typename M> \
2224 Vc_INTRINSIC enable_if<O == Operator::name_, SimdArray<T, N, V, VN>> \
2225 conditional_assign(SimdArray<T, N, V, VN> &lhs, M &&mask) \
2229 Vc_NOTHING_EXPECTING_SEMICOLON
2230 Vc_CONDITIONAL_ASSIGN(PostIncrement, lhs(mask)++);
2231 Vc_CONDITIONAL_ASSIGN( PreIncrement, ++lhs(mask));
2232 Vc_CONDITIONAL_ASSIGN(PostDecrement, lhs(mask)--);
2233 Vc_CONDITIONAL_ASSIGN( PreDecrement, --lhs(mask));
2234 #undef Vc_CONDITIONAL_ASSIGN
2238 template <
int L,
typename T, std::
size_t N,
typename V>
2239 inline enable_if<L == 4, void> transpose_impl(
2240 SimdArray<T, N, V, N> * Vc_RESTRICT r[],
2241 const TransposeProxy<SimdArray<T, N, V, N>, SimdArray<T, N, V, N>,
2242 SimdArray<T, N, V, N>, SimdArray<T, N, V, N>> &proxy)
2244 V *Vc_RESTRICT r2[L] = {&internal_data(*r[0]), &internal_data(*r[1]),
2245 &internal_data(*r[2]), &internal_data(*r[3])};
2247 &r2[0], TransposeProxy<V, V, V, V>{internal_data(std::get<0>(proxy.in)),
2248 internal_data(std::get<1>(proxy.in)),
2249 internal_data(std::get<2>(proxy.in)),
2250 internal_data(std::get<3>(proxy.in))});
2252 template <
int L,
typename T,
typename V>
2253 inline enable_if<(L == 2), void> transpose_impl(
2254 SimdArray<T, 4, V, 1> *Vc_RESTRICT r[],
2255 const TransposeProxy<SimdArray<T, 2, V, 1>, SimdArray<T, 2, V, 1>,
2256 SimdArray<T, 2, V, 1>, SimdArray<T, 2, V, 1>> &proxy)
2260 internal_data0(internal_data0(lo)) = internal_data0(std::get<0>(proxy.in));
2261 internal_data1(internal_data0(lo)) = internal_data0(std::get<1>(proxy.in));
2262 internal_data0(internal_data1(lo)) = internal_data0(std::get<2>(proxy.in));
2263 internal_data1(internal_data1(lo)) = internal_data0(std::get<3>(proxy.in));
2264 internal_data0(internal_data0(hi)) = internal_data1(std::get<0>(proxy.in));
2265 internal_data1(internal_data0(hi)) = internal_data1(std::get<1>(proxy.in));
2266 internal_data0(internal_data1(hi)) = internal_data1(std::get<2>(proxy.in));
2267 internal_data1(internal_data1(hi)) = internal_data1(std::get<3>(proxy.in));
2269 template <
int L,
typename T, std::
size_t N,
typename V>
2270 inline enable_if<(L == 4 && N > 1),
void> transpose_impl(
2271 SimdArray<T, N, V, 1> *Vc_RESTRICT r[],
2272 const TransposeProxy<SimdArray<T, N, V, 1>, SimdArray<T, N, V, 1>,
2273 SimdArray<T, N, V, 1>, SimdArray<T, N, V, 1>> &proxy)
2275 SimdArray<T, N, V, 1> *Vc_RESTRICT r0[L / 2] = {r[0], r[1]};
2276 SimdArray<T, N, V, 1> *Vc_RESTRICT r1[L / 2] = {r[2], r[3]};
2277 using H = SimdArray<T, 2>;
2279 &r0[0], TransposeProxy<H, H, H, H>{internal_data0(std::get<0>(proxy.in)),
2280 internal_data0(std::get<1>(proxy.in)),
2281 internal_data0(std::get<2>(proxy.in)),
2282 internal_data0(std::get<3>(proxy.in))});
2284 &r1[0], TransposeProxy<H, H, H, H>{internal_data1(std::get<0>(proxy.in)),
2285 internal_data1(std::get<1>(proxy.in)),
2286 internal_data1(std::get<2>(proxy.in)),
2287 internal_data1(std::get<3>(proxy.in))});
2339 template <
typename T,
size_t N,
typename V,
size_t VN>
2340 struct numeric_limits<
Vc::SimdArray<T, N, V, VN>> :
public numeric_limits<T> {
2347 static Vc_ALWAYS_INLINE Vc_CONST R lowest() noexcept
2349 return numeric_limits<T>::lowest();
2351 static Vc_ALWAYS_INLINE Vc_CONST R epsilon() noexcept
2353 return numeric_limits<T>::epsilon();
2355 static Vc_ALWAYS_INLINE Vc_CONST R round_error() noexcept
2357 return numeric_limits<T>::round_error();
2359 static Vc_ALWAYS_INLINE Vc_CONST R infinity() noexcept
2361 return numeric_limits<T>::infinity();
2363 static Vc_ALWAYS_INLINE Vc_CONST R quiet_NaN() noexcept
2365 return numeric_limits<T>::quiet_NaN();
2367 static Vc_ALWAYS_INLINE Vc_CONST R signaling_NaN() noexcept
2369 return numeric_limits<T>::signaling_NaN();
2371 static Vc_ALWAYS_INLINE Vc_CONST R denorm_min() noexcept
2373 return numeric_limits<T>::denorm_min();
#endif // VC_COMMON_SIMDARRAY_H_