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>>
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();
348 static constexpr std::size_t 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,
394 enable_if<Traits::simd_vector_size<M>::value == Size * Pieces> = nullarg)
395 : data0(Split::lo(rhs)), data1(Split::hi(rhs))
400 template <class M, class = enable_if<(Traits::is_simd_mask<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>>
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());
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))...)};
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) /
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_ bool isNotEmpty() const
Returns a logical OR of all components.
The main vector class for expressing data parallelism.
bool EntryType
The EntryType of masks is always bool, independent of T.
fixed_size_simd_mask< T, N > operator||(const SimdMaskArray &rhs) const
Returns the component-wise application of a logical OR to mask.
result_vector_type< L, R > operator|(L &&lhs, R &&rhs)
Applies | component-wise and concurrently.
result_vector_type< L, R > operator^(L &&lhs, R &&rhs)
Applies ^ component-wise and concurrently.
bool operator==(const SimdMaskArray &mask) const
Returns whether the two masks are equal in all components.
reference operator[](size_t index) noexcept
Return a smart reference to the boolean element at index index.
typename storage_type0::EntryType value_type
SimdMaskArray(const bool *mem, Flags f=Flags())
Load N boolean values from the consecutive addresses starting at mem.
SimdMaskArray(VectorSpecialInitializerZero zero)
Zero-initialize the new mask object (false).
fixed_size_simd_mask< T, N > operator &&(const SimdMaskArray &rhs) const
fixed_size_simd_mask< T, N > shifted(int amount) const
Returns a mask with components shifted by amount places.
void load(const bool *mem, Flags f)
Load N boolean values from the consecutive addresses starting at mem.
result_vector_type< L, R >::mask_type operator!=(L &&lhs, R &&rhs)
Applies != component-wise and concurrently.
SimdMaskArray & operator|=(const SimdMaskArray &rhs)
Modifies the mask using an OR operation with mask.
Identifies any possible SimdMaskArray<T, N> type (independent of const/volatile or reference) ...
int toInt() const
Convert the boolean components of the mask into bits of an integer.
static constexpr std::size_t size()
Returns the number of boolean components ( ) in a mask of this type.
SimdMaskArray(VectorSpecialInitializerOne one)
Initialize the new mask object to one (true).
Data-parallel mask type with user-defined number of boolean elements.
vectorentry_type VectorEntryType
void load(const bool *mem)
Load N boolean values from the consecutive addresses starting at mem.
bool operator!=(const SimdMaskArray &mask) const
Returns whether the two masks are different in at least one component.
static fixed_size_simd_mask< T, N > Zero()
Creates a new mask object initialized to zero/false.
SimdMaskArray & operator &=(const SimdMaskArray &rhs)
fixed_size_simd_mask< T, N > operator^(const SimdMaskArray &rhs) const
Returns the component-wise application of a binary XOR to mask.
Vc::Detail::ElementReference< SimdMaskArray > EntryReference
result_vector_type< L, R >::mask_type operator==(L &&lhs, R &&rhs)
Applies == component-wise and concurrently.
typename VectorTraits< T, Abi >::VectorEntryType VectorEntryType
The VectorEntryType, in contrast to EntryType, reveals information about the SIMD implementation...
static fixed_size_simd_mask< T, N > generate(const G &gen)
Generate a mask object from booleans returned from the function gen.
void store(bool *mem, Flags f) const
Store N boolean values to the consecutive addresses starting at mem.
SimdMaskArray & operator^=(const SimdMaskArray &rhs)
Modifies the mask using an XOR operation with mask.
result_vector_type< L, R > operator&(L &&lhs, R &&rhs)
Applies & component-wise and concurrently.
static fixed_size_simd_mask< T, N > One()
Creates a mask object initialized to one/true.
int firstOne() const
Returns the index of the first one in the mask.
int count() const
Returns how many components of the mask are true.
The main SIMD mask class.
fixed_size_simd_mask< T, N > operator!() const
Returns a mask with inverted components.
value_type operator[](size_t index) const noexcept
Return a copy of the boolean element at index index.
bool isEmpty() const
Returns true if components are false, false otherwise.
constexpr VectorSpecialInitializerZero Zero
The special object Vc::Zero can be used to construct Vector and Mask objects initialized to zero/fals...
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.
fixed_size_simd_mask< T, N > operator|(const SimdMaskArray &rhs) const
Returns the component-wise application of a binary OR to mask.
constexpr VectorSpecialInitializerOne One
The special object Vc::One can be used to construct Vector and Mask objects initialized to one/true...
constexpr std::size_t MemoryAlignment
Specifies the most conservative memory alignment necessary for aligned loads and stores of Vector typ...
SimdMaskArray(bool b)
Broadcast constructor.
void store(bool *mem) const
Store N boolean values to the consecutive addresses starting at mem.
fixed_size_simd_mask< T, N > operator &(const SimdMaskArray &rhs) const
bool isMix() const
Returns !isFull() && !isEmpty().
bool isFull() const
Returns a logical AND of all components.