28 #ifndef VC_COMMON_SIMDMASKARRAY_H_
29 #define VC_COMMON_SIMDMASKARRAY_H_
31 #include <type_traits>
33 #include "simdarrayhelper.h"
39 namespace Vc_VERSIONED_NAMESPACE
53 template <
typename T, std::
size_t N,
typename VectorType_>
54 class SimdMaskArray<T, N, VectorType_, N>
57 using VectorType = VectorType_;
58 using vector_type = VectorType;
59 using mask_type =
typename vector_type::Mask;
60 using storage_type = mask_type;
62 friend storage_type &internal_data(SimdMaskArray &m) {
return m.data; }
63 friend const storage_type &internal_data(
const SimdMaskArray &m) {
return m.data; }
65 static constexpr std::size_t size() {
return N; }
66 static constexpr std::size_t Size = size();
68 static_assert(Size == vector_type::Size,
"size mismatch");
70 using vectorentry_type =
typename mask_type::VectorEntryType;
71 using value_type =
typename mask_type::EntryType;
72 using Mask = mask_type;
73 using VectorEntryType = vectorentry_type;
74 using EntryType = value_type;
75 using EntryReference = Vc::Detail::ElementReference<storage_type, SimdMaskArray>;
76 using reference = EntryReference;
77 using Vector = fixed_size_simd<T, N>;
79 Vc_FREE_STORE_OPERATORS_ALIGNED(
alignof(mask_type));
82 SimdMaskArray() =
default;
85 SimdMaskArray(
const SimdMaskArray &) =
default;
86 SimdMaskArray(SimdMaskArray &&) =
default;
87 SimdMaskArray &operator=(
const SimdMaskArray &) =
default;
88 SimdMaskArray &operator=(SimdMaskArray &&) =
default;
91 Vc_INTRINSIC
explicit SimdMaskArray(VectorSpecialInitializerOne one) : data(one) {}
92 Vc_INTRINSIC
explicit SimdMaskArray(VectorSpecialInitializerZero zero) : data(zero) {}
93 Vc_INTRINSIC
explicit SimdMaskArray(
bool b) : data(b) {}
98 template <
class U,
class V,
class = enable_if<N == V::Size>>
99 Vc_INTRINSIC_L SimdMaskArray(
const SimdMaskArray<U, N, V> &x) Vc_INTRINSIC_R;
100 template <
class U,
class V,
class = enable_if<(N > V::Size && N <= 2 * V::Size)>,
102 Vc_INTRINSIC_L SimdMaskArray(
const SimdMaskArray<U, N, V> &x) Vc_INTRINSIC_R;
103 template <
class U,
class V,
class = enable_if<(N > 2 * V::Size && N <= 4 * V::Size)>,
104 class = U,
class = U>
105 Vc_INTRINSIC_L SimdMaskArray(
const SimdMaskArray<U, N, V> &x) Vc_INTRINSIC_R;
108 template <
typename M, std::
size_t Pieces, std::
size_t Index>
109 Vc_INTRINSIC_L SimdMaskArray(
110 Common::Segment<M, Pieces, Index> &&x,
111 enable_if<Traits::simd_vector_size<M>::value == Size * Pieces> = nullarg) Vc_INTRINSIC_R;
114 template <
class M,
class = enable_if<(Traits::is_simd_mask<M>::value &&
115 !Traits::isSimdMaskArray<M>::value &&
116 Traits::simd_vector_size<M>::value == Size)>>
117 Vc_INTRINSIC_L SimdMaskArray(M k) Vc_INTRINSIC_R;
120 template <
class U,
class A,
121 class = enable_if<Vc::Mask<U, A>::Size == N &&
122 !detail::is_fixed_size_abi<A>::value>>
125 return simd_cast<Vc::Mask<U, A>>(data);
127 operator fixed_size_simd_mask<T, N> &()
129 return static_cast<fixed_size_simd_mask<T, N> &
>(*this);
131 operator const fixed_size_simd_mask<T, N> &()
const
133 return static_cast<const fixed_size_simd_mask<T, N> &
>(*this);
137 template <
typename Flags = DefaultLoadTag>
138 Vc_INTRINSIC
explicit SimdMaskArray(
const bool *mem, Flags f = Flags())
143 Vc_INTRINSIC
void load(
const bool *mem) { data.load(mem); }
144 template <
typename Flags> Vc_INTRINSIC
void load(
const bool *mem, Flags f)
149 Vc_INTRINSIC
void store(
bool *mem)
const { data.store(mem); }
150 template <
typename Flags> Vc_INTRINSIC
void store(
bool *mem, Flags f)
const
156 Vc_INTRINSIC Vc_PURE
bool operator==(
const SimdMaskArray &rhs)
const
158 return data == rhs.data;
160 Vc_INTRINSIC Vc_PURE
bool operator!=(
const SimdMaskArray &rhs)
const
162 return data != rhs.data;
166 Vc_INTRINSIC Vc_PURE fixed_size_simd_mask<T, N> operator!()
const
168 return {private_init, !data};
172 Vc_INTRINSIC SimdMaskArray &operator&=(
const SimdMaskArray &rhs)
177 Vc_INTRINSIC SimdMaskArray &operator|=(
const SimdMaskArray &rhs)
182 Vc_INTRINSIC SimdMaskArray &operator^=(
const SimdMaskArray &rhs)
188 Vc_INTRINSIC Vc_PURE fixed_size_simd_mask<T, N>
operator&(
189 const SimdMaskArray &rhs)
const
191 return {private_init, data & rhs.data};
193 Vc_INTRINSIC Vc_PURE fixed_size_simd_mask<T, N>
operator|(
194 const SimdMaskArray &rhs)
const
196 return {private_init, data | rhs.data};
198 Vc_INTRINSIC Vc_PURE fixed_size_simd_mask<T, N>
operator^(
199 const SimdMaskArray &rhs)
const
201 return {private_init, data ^ rhs.data};
204 Vc_INTRINSIC Vc_PURE fixed_size_simd_mask<T, N> operator&&(
205 const SimdMaskArray &rhs)
const
207 return {private_init, data && rhs.data};
209 Vc_INTRINSIC Vc_PURE fixed_size_simd_mask<T, N> operator||(
210 const SimdMaskArray &rhs)
const
212 return {private_init, data || rhs.data};
215 Vc_INTRINSIC Vc_PURE
bool isFull()
const {
return data.isFull(); }
216 Vc_INTRINSIC Vc_PURE
bool isNotEmpty()
const {
return data.isNotEmpty(); }
217 Vc_INTRINSIC Vc_PURE
bool isEmpty()
const {
return data.isEmpty(); }
218 Vc_INTRINSIC Vc_PURE
bool isMix()
const {
return data.isMix(); }
220 Vc_INTRINSIC Vc_PURE
int shiftMask()
const {
return data.shiftMask(); }
222 Vc_INTRINSIC Vc_PURE
int toInt()
const {
return data.toInt(); }
226 static Vc_INTRINSIC value_type get(
const storage_type &k,
int i) noexcept
230 template <
typename U>
231 static Vc_INTRINSIC
void set(storage_type &k,
int i, U &&v) noexcept(
232 noexcept(std::declval<storage_type &>()[0] = std::declval<U>()))
234 k[i] = std::forward<U>(v);
244 Vc_INTRINSIC Vc_PURE reference operator[](
size_t index) noexcept
246 return {data, int(index)};
248 Vc_INTRINSIC Vc_PURE value_type operator[](
size_t index)
const noexcept
253 Vc_INTRINSIC Vc_PURE
int count()
const {
return data.count(); }
260 Vc_INTRINSIC Vc_PURE
int firstOne()
const {
return data.firstOne(); }
262 template <
typename G>
263 static Vc_INTRINSIC fixed_size_simd_mask<T, N> generate(
const G &gen)
265 return {private_init, mask_type::generate(gen)};
268 Vc_INTRINSIC Vc_PURE fixed_size_simd_mask<T, N>
shifted(
int amount)
const
270 return {private_init, data.shifted(amount)};
274 template <
typename Op,
typename... Args>
275 static Vc_INTRINSIC fixed_size_simd_mask<T, N> fromOperation(Op op, Args &&... args)
277 fixed_size_simd_mask<T, N> r;
278 Common::unpackArgumentsAuto(op, r.data, std::forward<Args>(args)...);
283 Vc_INTRINSIC SimdMaskArray(private_init_t, mask_type &&x) : data(std::move(x)) {}
289 alignas(
static_cast<std::size_t
>(
290 Common::BoundedAlignment<Common::NextPowerOfTwo<N>::value *
sizeof(VectorType_) /
291 VectorType_::size()>::value)) storage_type data;
294 template <
typename T, std::
size_t N,
typename VectorType> constexpr std::size_t SimdMaskArray<T, N, VectorType, N>::Size;
295 template <
typename T, std::
size_t N,
typename VectorType>
322 template <
typename T,
size_t N,
typename V,
size_t Wt>
325 static constexpr std::size_t N0 = Common::left_size<N>();
327 using Split = Common::Split<N0>;
330 using storage_type0 = fixed_size_simd_mask<T, N0>;
331 using storage_type1 = fixed_size_simd_mask<T, N - N0>;
332 static_assert(storage_type0::size() == N0,
"");
334 using vector_type = fixed_size_simd<T, N>;
336 friend storage_type0 &internal_data0(SimdMaskArray &m) {
return m.data0; }
337 friend storage_type1 &internal_data1(SimdMaskArray &m) {
return m.data1; }
338 friend const storage_type0 &internal_data0(
const SimdMaskArray &m) {
return m.data0; }
339 friend const storage_type1 &internal_data1(
const SimdMaskArray &m) {
return m.data1; }
341 using mask_type = SimdMaskArray;
344 static constexpr std::size_t
size() {
return N; }
346 static constexpr std::size_t Size = size();
352 static_assert(Size == vector_type::Size,
"size mismatch");
384 template <
typename U,
typename W>
386 : data0(Split::lo(rhs)), data1(Split::hi(rhs))
391 template <
typename M, std::
size_t Pieces, std::
size_t Index>
393 Common::Segment<M, Pieces, Index> &&rhs,
395 : data0(Split::lo(rhs)), data1(Split::hi(rhs))
400 template <
class M,
class = enable_if<(Traits::is_simd_mask<M>::value &&
401 !Traits::isSimdMaskArray<M>::value &&
402 Traits::simd_vector_size<M>::value == Size)>>
403 Vc_INTRINSIC SimdMaskArray(M k) : data0(Split::lo(k)), data1(Split::hi(k))
408 template <
class U,
class A,
409 class = enable_if<Vc::Mask<U, A>::Size == N &&
410 !detail::is_fixed_size_abi<A>::value>>
413 return simd_cast<Vc::Mask<U, A>>(data0, data1);
415 Vc_INTRINSIC
operator fixed_size_simd_mask<T, N> &()
417 return static_cast<fixed_size_simd_mask<T, N> &
>(*this);
419 Vc_INTRINSIC
operator const fixed_size_simd_mask<T, N> &()
const
421 return static_cast<const fixed_size_simd_mask<T, N> &
>(*this);
426 : data0(one), data1(one)
431 : data0(zero), data1(zero)
457 template <
typename Flags = DefaultLoadTag>
468 Vc_INTRINSIC
void load(
const bool *mem)
471 data1.load(mem + storage_type0::size());
480 template <
typename Flags> Vc_INTRINSIC
void load(
const bool *mem, Flags f)
483 data1.load(mem + storage_type0::size(), f);
491 Vc_INTRINSIC
void store(
bool *mem)
const
494 data1.store(mem + storage_type0::size());
503 template <
typename Flags> Vc_INTRINSIC
void store(
bool *mem, Flags f)
const
506 data1.store(mem + storage_type0::size(), f);
513 return data0 == mask.data0 && data1 == mask.data1;
518 return data0 != mask.data0 || data1 != mask.data1;
524 return {!data0, !data1};
553 return {data0 & rhs.data0, data1 & rhs.data1};
559 return {data0 | rhs.data0, data1 | rhs.data1};
565 return {data0 ^ rhs.data0, data1 ^ rhs.data1};
572 return {data0 && rhs.data0, data1 && rhs.data1};
578 return {data0 || rhs.data0, data1 || rhs.data1};
582 Vc_INTRINSIC Vc_PURE
bool isFull()
const {
return data0.isFull() && data1.isFull(); }
584 Vc_INTRINSIC Vc_PURE
bool isNotEmpty()
const {
return data0.isNotEmpty() || data1.isNotEmpty(); }
586 Vc_INTRINSIC Vc_PURE
bool isEmpty()
const {
return data0.isEmpty() && data1.isEmpty(); }
588 Vc_INTRINSIC Vc_PURE
bool isMix()
const {
return !isFull() && !isEmpty(); }
591 Vc_INTRINSIC Vc_PURE
int toInt()
const
593 return data0.toInt() | (data1.toInt() << data0.size());
598 static Vc_INTRINSIC value_type get(
const SimdMaskArray &o,
int i) noexcept
600 if (i <
int(o.data0.size())) {
603 return o.data1[i - o.data0.size()];
606 template <
typename U>
607 static Vc_INTRINSIC
void set(SimdMaskArray &o,
int i, U &&v) noexcept(
608 noexcept(std::declval<storage_type0 &>()[0] = std::declval<U>()) &&
609 noexcept(std::declval<storage_type1 &>()[0] = std::declval<U>()))
611 if (i <
int(o.data0.size())) {
612 o.data0[i] = std::forward<U>(v);
614 o.data1[i - o.data0.size()] = std::forward<U>(v);
627 Vc_INTRINSIC Vc_PURE reference
operator[](
size_t index) noexcept
629 return {*
this, int(index)};
641 return get(*
this, index);
645 Vc_INTRINSIC Vc_PURE
int count()
const {
return data0.count() + data1.count(); }
649 if (data0.isEmpty()) {
650 return data1.firstOne() + storage_type0::size();
652 return data0.firstOne();
656 template <
typename G>
659 return {storage_type0::generate(gen),
660 storage_type1::generate([&](std::size_t i) {
return gen(i + N0); })};
666 if (Vc_IS_UNLIKELY(amount == 0)) {
669 return generate([&](
unsigned i) {
671 const unsigned j = i + amount;
672 return j < size() ? get(*
this, j) :
false;
677 template <
typename Op,
typename... Args>
681 storage_type0::fromOperation(op, Split::lo(args)...),
684 storage_type1::fromOperation(op, Split::hi(std::forward<Args>(args))...)};
689 Vc_INTRINSIC SimdMaskArray(storage_type0 &&x, storage_type1 &&y)
690 : data0(std::move(x)), data1(std::move(y))
698 alignas(
static_cast<std::size_t
>(
699 Common::BoundedAlignment<Common::NextPowerOfTwo<N>::value *
sizeof(V) /
700 V::size()>::value)) storage_type0 data0;
703 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
705 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
715 #include "simd_cast_caller.tcc"
717 #endif // VC_COMMON_SIMDMASKARRAY_H_