28#ifndef VC_COMMON_SIMDMASKARRAY_H_
29#define VC_COMMON_SIMDMASKARRAY_H_
33#include "simdarrayhelper.h"
39namespace Vc_VERSIONED_NAMESPACE
53template <
typename T, std::
size_t N,
typename VectorType_>
54class 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();
67 static constexpr std::size_t
MemoryAlignment = storage_type::MemoryAlignment;
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) {}
94 Vc_INTRINSIC
static SimdMaskArray
Zero() {
return {private_init, storage_type::Zero()}; }
95 Vc_INTRINSIC
static SimdMaskArray
One() {
return {private_init, storage_type::One()}; }
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;
294template <
typename T, std::
size_t N,
typename VectorType>
constexpr std::size_t SimdMaskArray<T, N, VectorType, N>::Size;
295template <
typename T, std::
size_t N,
typename VectorType>
296constexpr std::size_t SimdMaskArray<T, N, VectorType, N>::MemoryAlignment;
322template <
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>;
332 static_assert(storage_type0::size() == N0,
"");
344 static constexpr std::size_t
size() {
return N; }
346 static constexpr std::size_t Size = size();
349 storage_type0::MemoryAlignment > storage_type1::MemoryAlignment
350 ? storage_type0::MemoryAlignment
351 : storage_type1::MemoryAlignment;
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)
440 return {storage_type0::Zero(), storage_type1::Zero()};
445 return {storage_type0::One(), storage_type1::One()};
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;
703template <
typename T, std::
size_t N,
typename V, std::
size_t M>
704constexpr std::size_t SimdMaskArray<T, N, V, M>::Size;
705template <
typename T, std::
size_t N,
typename V, std::
size_t M>
706constexpr std::size_t SimdMaskArray<T, N, V, M>::MemoryAlignment;
715#include "simd_cast_caller.tcc"
The main SIMD mask class.
typename VectorTraits< T, Abi >::VectorEntryType VectorEntryType
The VectorEntryType, in contrast to EntryType, reveals information about the SIMD implementation.
bool EntryType
The EntryType of masks is always bool, independent of T.
Data-parallel mask type with user-defined number of boolean elements.
fixed_size_simd_mask< T, N > operator&(const SimdMaskArray &rhs) const
Returns the component-wise application of a binary AND to mask.
SimdMaskArray(bool b)
Broadcast constructor.
void store(bool *mem) const
Store N boolean values to the consecutive addresses starting at mem.
int count() const
Returns how many components of the mask are true.
typename storage_type0::EntryType value_type
The EntryType of masks is always bool, independent of T.
SimdMaskArray & operator|=(const SimdMaskArray &rhs)
Modifies the mask using an OR operation with mask.
static fixed_size_simd_mask< T, N > Zero()
Creates a new mask object initialized to zero/false.
bool isMix() const
Returns !isFull() && !isEmpty().
fixed_size_simd_mask< T, N > operator^(const SimdMaskArray &rhs) const
Returns the component-wise application of a binary XOR to mask.
bool isNotEmpty() const
Returns a logical OR of all components.
static fixed_size_simd_mask< T, N > One()
Creates a mask object initialized to one/true.
vectorentry_type VectorEntryType
The VectorEntryType, in contrast to EntryType, reveals information about the SIMD implementation.
bool operator!=(const SimdMaskArray &mask) const
Returns whether the two masks are different in at least one component.
void load(const bool *mem)
Load N boolean values from the consecutive addresses starting at mem.
SimdMaskArray(const bool *mem, Flags f=Flags())
Load N boolean values from the consecutive addresses starting at mem.
static constexpr std::size_t size()
Returns the number of boolean components ( ) in a mask of this type.
fixed_size_simd_mask< T, N > operator&&(const SimdMaskArray &rhs) const
Returns the component-wise application of a logical AND to mask.
value_type operator[](size_t index) const noexcept
Return a copy of the boolean element at index index.
SimdMaskArray(VectorSpecialInitializerOne one)
Initialize the new mask object to one (true).
Vc::Detail::ElementReference< SimdMaskArray > EntryReference
The reference wrapper type used for accessing individual mask components.
fixed_size_simd_mask< T, N > operator||(const SimdMaskArray &rhs) const
Returns the component-wise application of a logical OR to mask.
SimdMaskArray & operator^=(const SimdMaskArray &rhs)
Modifies the mask using an XOR operation with mask.
int toInt() const
Convert the boolean components of the mask into bits of an integer.
static fixed_size_simd_mask< T, N > generate(const G &gen)
Generate a mask object from booleans returned from the function gen.
fixed_size_simd_mask< T, N > operator!() const
Returns a mask with inverted components.
void store(bool *mem, Flags f) const
Store N boolean values to the consecutive addresses starting at mem.
void load(const bool *mem, Flags f)
Load N boolean values from the consecutive addresses starting at mem.
fixed_size_simd_mask< T, N > shifted(int amount) const
Returns a mask with components shifted by amount places.
SimdMaskArray()=default
Construct a zero-initialized vector object.
bool isEmpty() const
Returns true if components are false, false otherwise.
int firstOne() const
Returns the index of the first one in the mask.
bool isFull() const
Returns a logical AND of all components.
reference operator[](size_t index) noexcept
Return a smart reference to the boolean element at index index.
bool operator==(const SimdMaskArray &mask) const
Returns whether the two masks are equal in all components.
value_type EntryType
The EntryType of masks is always bool, independent of T.
SimdMaskArray & operator&=(const SimdMaskArray &rhs)
Modifies the mask using an AND operation with mask.
SimdMaskArray(VectorSpecialInitializerZero zero)
Zero-initialize the new mask object (false).
fixed_size_simd_mask< T, N > operator|(const SimdMaskArray &rhs) const
Returns the component-wise application of a binary OR to mask.
The main vector class for expressing data parallelism.
Adapter< S, T, N > shifted(const Adapter< S, T, N > &a, int shift)
Returns a new vectorized object where each entry is shifted by shift.
constexpr VectorSpecialInitializerOne One
The special object Vc::One can be used to construct Vector and Mask objects initialized to one/true.
constexpr VectorSpecialInitializerZero Zero
The special object Vc::Zero can be used to construct Vector and Mask objects initialized to zero/fals...
constexpr std::size_t MemoryAlignment
Specifies the most conservative memory alignment necessary for aligned loads and stores of Vector typ...
The value member will either be the number of SIMD vector entries or 0 if T is not a SIMD type.